Compare commits

...

124 Commits

Author SHA1 Message Date
renovate[bot]
5fb34f3c91 Merge d159d4b0dd into 4168f43e3e 2025-07-09 15:03:20 +00:00
renovate[bot]
d159d4b0dd fix(deps): update all non-major dependencies 2025-07-09 15:03:17 +00:00
Pujit Mehrotra
4168f43e3e fix: duplicated header logo after api stops (#1493)
Move legacy header logo omission from API file modifier to plg install
step to avoid breaking rollback (ie upon `unraid-api stop`) due to web
component upgrade.

Tested on 7.1.4 & 7.2.0-beta.0.16

Testing & Reproduction procedure:

1. Install connect plugin
2. Run `unraid-api stop` on server
3. Refresh page. Before Unraid 7.2, Plugin versions prior to this will
display a duplicated logo that blocks the nav menu. Now, it will not.
Plugin uninstall behavior remains unchanged.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* The plugin installation process now updates the header logo by
removing the old logo from the interface during installation.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-09 10:59:10 -04:00
github-actions[bot]
20de3ec8d6 chore(main): release 4.9.2 (#1488)
🤖 I have created a release *beep* *boop*
---


## [4.9.2](https://github.com/unraid/api/compare/v4.9.1...v4.9.2)
(2025-07-09)


### Bug Fixes

* invalid configs no longer crash API
([#1491](https://github.com/unraid/api/issues/1491))
([6bf3f77](6bf3f77638))
* invalid state for unraid plugin
([#1492](https://github.com/unraid/api/issues/1492))
([39b8f45](39b8f453da))
* release note escaping
([5b6bcb6](5b6bcb6043))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-09 09:23:25 -04:00
Eli Bosley
39b8f453da fix: invalid state for unraid plugin (#1492)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Improved connection status handling by introducing a new service that
writes connection status to a JSON file for enhanced integration.
* Updated system components to read connection status and allowed
origins from the new JSON file, ensuring more reliable and up-to-date
information.

* **Chores**
* Expanded allowed Bash command permissions to include commands starting
with "mv:".
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-09 09:21:43 -04:00
Eli Bosley
6bf3f77638 fix: invalid configs no longer crash API (#1491)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved error handling when loading and parsing configuration files,
preventing crashes and ensuring fallback to default settings if issues
occur.
* Enhanced logging for configuration errors, including warnings for
empty files and detailed error messages for JSON parsing failures.
* Added error handling to plugin listing to avoid failures when
configuration loading encounters errors.

* **Chores**
* Updated permissions to allow linting only for the `./api` package
using a filtered command.

* **Tests**
* Added comprehensive tests for configuration loading, parsing,
persistence, and updating, covering various file states and error
scenarios.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-09 08:50:43 -04:00
Eli Bosley
a79d049865 chore: lint for renovate PR (#1481) 2025-07-08 17:01:49 -04:00
Eli Bosley
5b6bcb6043 fix: release note escaping 2025-07-08 16:41:05 -04:00
github-actions[bot]
6ee3cae962 chore(main): release 4.9.1 (#1487)
🤖 I have created a release *beep* *boop*
---


## [4.9.1](https://github.com/unraid/api/compare/v4.9.0...v4.9.1)
(2025-07-08)


### Bug Fixes

* **HeaderOsVersion:** adjust top margin for header component
([#1485](https://github.com/unraid/api/issues/1485))
([862b54d](862b54de8c))
* sign out doesn't work
([#1486](https://github.com/unraid/api/issues/1486))
([f3671c3](f3671c3e07))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-08 16:30:00 -04:00
Eli Bosley
f3671c3e07 fix: sign out doesn't work (#1486)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Improved handling of Connect account sign-in and sign-out with
persistent mutation instances for better status updates and error
reporting.

* **Chores**
* Expanded allowed command patterns in configuration for development,
build, and testing tasks.

* **Tests**
* Enhanced mutation mocks in component tests to increase test
reliability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-08 16:28:38 -04:00
Zack Spear
862b54de8c fix(HeaderOsVersion): adjust top margin for header component (#1485)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Style**
  * Increased top margin in the OS version header for improved spacing.
* Updated user profile container to use padding instead of margin for
better layout consistency.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-08 16:11:02 -04:00
github-actions[bot]
9624ca5c39 chore(main): release 4.9.0 (#1378)
🤖 I have created a release *beep* *boop*
---


## [4.9.0](https://github.com/unraid/api/compare/v4.8.0...v4.9.0)
(2025-07-08)


### Features

* add graphql resource for API plugins
([#1420](https://github.com/unraid/api/issues/1420))
([642a220](642a220c3a))
* add management page for API keys
([#1408](https://github.com/unraid/api/issues/1408))
([0788756](0788756b91))
* add rclone ([#1362](https://github.com/unraid/api/issues/1362))
([5517e75](5517e7506b))
* API key management
([#1407](https://github.com/unraid/api/issues/1407))
([d37dc3b](d37dc3bce2))
* api plugin management via CLI
([#1416](https://github.com/unraid/api/issues/1416))
([3dcbfbe](3dcbfbe489))
* build out docker components
([#1427](https://github.com/unraid/api/issues/1427))
([711cc9a](711cc9ac92))
* docker and info resolver issues
([#1423](https://github.com/unraid/api/issues/1423))
([9901039](9901039a38))
* fix shading in UPC to be less severe
([#1438](https://github.com/unraid/api/issues/1438))
([b7c2407](b7c2407840))
* info resolver cleanup
([#1425](https://github.com/unraid/api/issues/1425))
([1b279bb](1b279bbab3))
* initial codeql setup
([#1390](https://github.com/unraid/api/issues/1390))
([2ade7eb](2ade7eb527))
* initialize claude code in codebse
([#1418](https://github.com/unraid/api/issues/1418))
([b6c4ee6](b6c4ee6eb4))
* move api key fetching to use api key service
([#1439](https://github.com/unraid/api/issues/1439))
([86bea56](86bea56272))
* move to cron v4 ([#1428](https://github.com/unraid/api/issues/1428))
([b8035c2](b8035c207a))
* move to iframe for changelog
([#1388](https://github.com/unraid/api/issues/1388))
([fcd6fbc](fcd6fbcdd4))
* native slackware package
([#1381](https://github.com/unraid/api/issues/1381))
([4f63b4c](4f63b4cf3b))
* send active unraid theme to docs
([#1400](https://github.com/unraid/api/issues/1400))
([f71943b](f71943b62b))
* slightly better watch mode
([#1398](https://github.com/unraid/api/issues/1398))
([881f1e0](881f1e0960))
* upgrade nuxt-custom-elements
([#1461](https://github.com/unraid/api/issues/1461))
([345e83b](345e83bfb0))
* use bigint instead of long
([#1403](https://github.com/unraid/api/issues/1403))
([574d572](574d572d65))


### Bug Fixes

* activation indicator removed
([5edfd82](5edfd823b8))
* alignment of settings on ManagementAccess settings page
([#1421](https://github.com/unraid/api/issues/1421))
([70c790f](70c790ff89))
* allow rclone to fail to initialize
([#1453](https://github.com/unraid/api/issues/1453))
([7c6f02a](7c6f02a5cb))
* always download 7.1 versioned files for patching
([edc0d15](edc0d1578b))
* api `pnpm type-check`
([#1442](https://github.com/unraid/api/issues/1442))
([3122bdb](3122bdb953))
* **api:** connect config `email` validation
([#1454](https://github.com/unraid/api/issues/1454))
([b9a1b9b](b9a1b9b087))
* backport
unraid/webgui[#2269](https://github.com/unraid/api/issues/2269) rc.nginx
update ([#1436](https://github.com/unraid/api/issues/1436))
([a7ef06e](a7ef06ea25))
* bigint
([e54d27a](e54d27aede))
* config migration from `myservers.cfg`
([#1440](https://github.com/unraid/api/issues/1440))
([c4c9984](c4c99843c7))
* **connect:** fatal race-condition in websocket disposal
([#1462](https://github.com/unraid/api/issues/1462))
([0ec0de9](0ec0de982f))
* **connect:** mothership connection
([#1464](https://github.com/unraid/api/issues/1464))
([7be8bc8](7be8bc84d3))
* console hidden
([9b85e00](9b85e009b8))
* debounce is too long
([#1426](https://github.com/unraid/api/issues/1426))
([f12d231](f12d231e63))
* delete legacy connect keys and ensure description
([22fe91c](22fe91cd56))
* **deps:** pin dependencies
([#1465](https://github.com/unraid/api/issues/1465))
([ba75a40](ba75a409a4))
* **deps:** pin dependencies
([#1470](https://github.com/unraid/api/issues/1470))
([412b329](412b32996d))
* **deps:** storybook v9
([#1476](https://github.com/unraid/api/issues/1476))
([45bb49b](45bb49bcd6))
* **deps:** update all non-major dependencies
([#1366](https://github.com/unraid/api/issues/1366))
([291ee47](291ee475fb))
* **deps:** update all non-major dependencies
([#1379](https://github.com/unraid/api/issues/1379))
([8f70326](8f70326d0f))
* **deps:** update all non-major dependencies
([#1389](https://github.com/unraid/api/issues/1389))
([cb43f95](cb43f95233))
* **deps:** update all non-major dependencies
([#1399](https://github.com/unraid/api/issues/1399))
([68df344](68df344a4b))
* **deps:** update dependency @types/diff to v8
([#1393](https://github.com/unraid/api/issues/1393))
([00da27d](00da27d04f))
* **deps:** update dependency cache-manager to v7
([#1413](https://github.com/unraid/api/issues/1413))
([9492c2a](9492c2ae6a))
* **deps:** update dependency commander to v14
([#1394](https://github.com/unraid/api/issues/1394))
([106ea09](106ea09399))
* **deps:** update dependency diff to v8
([#1386](https://github.com/unraid/api/issues/1386))
([e580f64](e580f646a5))
* **deps:** update dependency dotenv to v17
([#1474](https://github.com/unraid/api/issues/1474))
([d613bfa](d613bfa041))
* **deps:** update dependency lucide-vue-next to ^0.509.0
([#1383](https://github.com/unraid/api/issues/1383))
([469333a](469333acd4))
* **deps:** update dependency marked to v16
([#1444](https://github.com/unraid/api/issues/1444))
([453a5b2](453a5b2c95))
* **deps:** update dependency shadcn-vue to v2
([#1302](https://github.com/unraid/api/issues/1302))
([26ecf77](26ecf779e6))
* **deps:** update dependency vue-sonner to v2
([#1401](https://github.com/unraid/api/issues/1401))
([53ca414](53ca41404f))
* disable file changes on Unraid 7.2
([#1382](https://github.com/unraid/api/issues/1382))
([02de89d](02de89d130))
* do not start API with doinst.sh
([7d88b33](7d88b3393c))
* do not uninstall fully on 7.2
([#1484](https://github.com/unraid/api/issues/1484))
([2263881](22638811a9))
* drop console with terser
([a87d455](a87d455bac))
* error logs from `cloud` query when connect is not installed
([#1450](https://github.com/unraid/api/issues/1450))
([719f460](719f460016))
* flash backup integration with Unraid Connect config
([#1448](https://github.com/unraid/api/issues/1448))
([038c582](038c582aed))
* header padding regression
([#1477](https://github.com/unraid/api/issues/1477))
([e791cc6](e791cc680d))
* incorrect state merging in redux store
([#1437](https://github.com/unraid/api/issues/1437))
([17b7428](17b7428779))
* lanip copy button not present
([#1459](https://github.com/unraid/api/issues/1459))
([a280786](a2807864ac))
* move to bigint scalar
([b625227](b625227913))
* node_modules dir removed on plugin update
([#1406](https://github.com/unraid/api/issues/1406))
([7b005cb](7b005cbbf6))
* omit Connect actions in UPC when plugin is not installed
([#1417](https://github.com/unraid/api/issues/1417))
([8c8a527](8c8a5276b4))
* parsing of `ssoEnabled` in state.php
([#1455](https://github.com/unraid/api/issues/1455))
([f542c8e](f542c8e0bd))
* pin ranges ([#1460](https://github.com/unraid/api/issues/1460))
([f88400e](f88400eea8))
* pr plugin promotion workflow
([#1456](https://github.com/unraid/api/issues/1456))
([13bd9bb](13bd9bb567))
* proper fallback if missing paths config modules
([7067e9e](7067e9e3dd))
* rc.unraid-api now cleans up older dependencies
([#1404](https://github.com/unraid/api/issues/1404))
([83076bb](83076bb940))
* remote access lifecycle during boot & shutdown
([#1422](https://github.com/unraid/api/issues/1422))
([7bc583b](7bc583b186))
* sign out correctly on error
([#1452](https://github.com/unraid/api/issues/1452))
([d08fc94](d08fc94afb))
* simplify usb listing
([#1402](https://github.com/unraid/api/issues/1402))
([5355115](5355115af2))
* theme issues when sent from graph
([#1424](https://github.com/unraid/api/issues/1424))
([75ad838](75ad8381bd))
* **ui:** notifications positioning regression
([#1445](https://github.com/unraid/api/issues/1445))
([f73e5e0](f73e5e0058))
* use some instead of every for connect detection
([9ce2fee](9ce2fee380))


### Reverts

* revert package.json dependency updates from commit 711cc9a for api and
packages/*
([94420e4](94420e4d45))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-08 15:45:49 -04:00
Eli Bosley
22638811a9 fix: do not uninstall fully on 7.2 (#1484)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Uninstallation process now adapts based on Unraid version: for version
7.2 or higher, users receive a notification and are prompted to reboot
to complete plugin removal.
* **Bug Fixes**
* Improved handling of plugin removal to ensure compatibility with
different Unraid versions and prevent unintended reinstalls.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-08 15:44:30 -04:00
Eli Bosley
5edfd823b8 fix: activation indicator removed 2025-07-08 15:42:41 -04:00
Michael Datelle
0379845618 refactor: update welcome modal and color picker (#1466)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added a new "full" size option to dialogs, allowing dialogs to fill
the entire screen.
* Introduced a prop to control the visibility of the close button on
dialogs.

* **Refactor**
* Updated the Welcome Modal to use the new Dialog component with
improved layout and slot usage.
* Reworked dialog content structure for better flexibility and styling.

* **Tests**
* Updated tests to reflect the switch from the Modal component to the
Dialog component, including new mocks and assertions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: mdatelle <mike@datelle.net>
Co-authored-by: Eli Bosley <ekbosley@gmail.com>
2025-07-08 15:24:29 -04:00
Pujit Mehrotra
5a3e7a91eb chore: inform users to refresh page if nchan breaks (#1482)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added an informational message during plugin installation to guide
users on when it is safe to refresh the page.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-08 15:10:43 -04:00
Eli Bosley
aefcc762ca chore: remove vue-jsx 2025-07-08 14:58:09 -04:00
Eli Bosley
07b59b0970 chore: remove jsx plugin for webcomponents (#1480)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
  * Updated internal configuration to remove unused plugin dependencies.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-08 14:57:19 -04:00
Eli Bosley
91883e2b47 chore: add plugin links to readme (#1479)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Added a prominently displayed "Plugin Downloads" section to the
README, featuring large badge-style download buttons and direct links
for both production and staging plugin files.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-08 14:23:46 -04:00
renovate[bot]
e57ecd551f chore(deps): update dependency vite to v7 (#1434)
This PR contains the following updates:

| Package | Change | Age | Confidence |
|---|---|---|---|
| [vite](https://vite.dev)
([source](https://redirect.github.com/vitejs/vite/tree/HEAD/packages/vite))
| [`6.3.5` ->
`7.0.3`](https://renovatebot.com/diffs/npm/vite/6.3.5/7.0.3) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/vite/7.0.3?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/vite/6.3.5/7.0.3?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>vitejs/vite (vite)</summary>

###
[`v7.0.3`](https://redirect.github.com/vitejs/vite/blob/HEAD/packages/vite/CHANGELOG.md#small-703-2025-07-08-small)

[Compare
Source](https://redirect.github.com/vitejs/vite/compare/v7.0.2...v7.0.3)

##### Bug Fixes

- **client:** protect against window being defined but addEv undefined
([#&#8203;20359](https://redirect.github.com/vitejs/vite/issues/20359))
([31d1467](31d1467cf0))
- **define:** replace optional values
([#&#8203;20338](https://redirect.github.com/vitejs/vite/issues/20338))
([9465ae1](9465ae1378))
- **deps:** update all non-major dependencies
([#&#8203;20366](https://redirect.github.com/vitejs/vite/issues/20366))
([43ac73d](43ac73da27))

##### Miscellaneous Chores

- **deps:** update dependency dotenv to v17
([#&#8203;20325](https://redirect.github.com/vitejs/vite/issues/20325))
([45040d4](45040d4807))
- **deps:** update dependency rolldown to ^1.0.0-beta.24
([#&#8203;20365](https://redirect.github.com/vitejs/vite/issues/20365))
([5ab25e7](5ab25e73a2))
- use `n/prefer-node-protocol` rule
([#&#8203;20368](https://redirect.github.com/vitejs/vite/issues/20368))
([38bb268](38bb268cde))

##### Code Refactoring

- minor changes to reduce diff between normal Vite and rolldown-vite
([#&#8203;20354](https://redirect.github.com/vitejs/vite/issues/20354))
([2e8050e](2e8050e4cd))

###
[`v7.0.2`](https://redirect.github.com/vitejs/vite/blob/HEAD/packages/vite/CHANGELOG.md#small-702-2025-07-04-small)

[Compare
Source](https://redirect.github.com/vitejs/vite/compare/v7.0.1...v7.0.2)

##### Bug Fixes

- **css:** resolve relative paths in sass, revert
[#&#8203;20300](https://redirect.github.com/vitejs/vite/issues/20300)
([#&#8203;20349](https://redirect.github.com/vitejs/vite/issues/20349))
([db8bd41](db8bd412a8))

###
[`v7.0.1`](https://redirect.github.com/vitejs/vite/blob/HEAD/packages/vite/CHANGELOG.md#small-701-2025-07-03-small)

[Compare
Source](https://redirect.github.com/vitejs/vite/compare/v7.0.0...v7.0.1)

##### Bug Fixes

- **css:** skip resolving resolved paths in sass
([#&#8203;20300](https://redirect.github.com/vitejs/vite/issues/20300))
([ac528a4](ac528a44c3))
- **deps:** update all non-major dependencies
([#&#8203;20324](https://redirect.github.com/vitejs/vite/issues/20324))
([3e81af3](3e81af38a8))
- **types:** add a global interface for Worker
([#&#8203;20243](https://redirect.github.com/vitejs/vite/issues/20243))
([37bdfc1](37bdfc18f4))

##### Miscellaneous Chores

- **deps:** update rolldown-related dependencies
([#&#8203;20323](https://redirect.github.com/vitejs/vite/issues/20323))
([30d2f1b](30d2f1b38c))
- fix typos and grammatical errors across documentation and comments
([#&#8203;20337](https://redirect.github.com/vitejs/vite/issues/20337))
([c1c951d](c1c951dcc3))
- group commits by category in changelog
([#&#8203;20310](https://redirect.github.com/vitejs/vite/issues/20310))
([41e83f6](41e83f62b1))
- rearrange 7.0 changelog
([#&#8203;20280](https://redirect.github.com/vitejs/vite/issues/20280))
([eafd28a](eafd28ac88))

###
[`v7.0.0`](https://redirect.github.com/vitejs/vite/blob/HEAD/packages/vite/CHANGELOG.md#700-2025-06-24)

[Compare
Source](https://redirect.github.com/vitejs/vite/compare/v6.3.5...v7.0.0)

- fix: keep `import.meta.url` in bundled Vite
([#&#8203;20235](https://redirect.github.com/vitejs/vite/issues/20235))
([3bf3a8a](3bf3a8ab00)),
closes
[#&#8203;20235](https://redirect.github.com/vitejs/vite/issues/20235)
- fix(deps): update all non-major dependencies
([#&#8203;20271](https://redirect.github.com/vitejs/vite/issues/20271))
([6b64d63](6b64d63d70)),
closes
[#&#8203;20271](https://redirect.github.com/vitejs/vite/issues/20271)
- fix(module-runner): export `ssrExportNameKey`
([#&#8203;20266](https://redirect.github.com/vitejs/vite/issues/20266))
([ac302a7](ac302a7290)),
closes
[#&#8203;20266](https://redirect.github.com/vitejs/vite/issues/20266)
- fix(module-runner): expose `normalizeModuleId`
([#&#8203;20277](https://redirect.github.com/vitejs/vite/issues/20277))
([9b98dcb](9b98dcbf75)),
closes
[#&#8203;20277](https://redirect.github.com/vitejs/vite/issues/20277)
- feat(types): use terser types from terser package
([#&#8203;20274](https://redirect.github.com/vitejs/vite/issues/20274))
([a5799fa](a5799fa74c)),
closes
[#&#8203;20274](https://redirect.github.com/vitejs/vite/issues/20274)
- chore: "indentity" → "identity" in test description
([#&#8203;20225](https://redirect.github.com/vitejs/vite/issues/20225))
([ea9aed7](ea9aed7ebc)),
closes
[#&#8203;20225](https://redirect.github.com/vitejs/vite/issues/20225)
- chore: typos in comments
([#&#8203;20259](https://redirect.github.com/vitejs/vite/issues/20259))
([b135918](b135918b91)),
closes
[#&#8203;20259](https://redirect.github.com/vitejs/vite/issues/20259)
- chore(deps): update rolldown-related dependencies
([#&#8203;20270](https://redirect.github.com/vitejs/vite/issues/20270))
([f7377c3](f7377c3eae)),
closes
[#&#8203;20270](https://redirect.github.com/vitejs/vite/issues/20270)
- perf(utils): improve performance of `numberToPos`
([#&#8203;20244](https://redirect.github.com/vitejs/vite/issues/20244))
([3f46901](3f469012ad)),
closes
[#&#8203;20244](https://redirect.github.com/vitejs/vite/issues/20244)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC42Mi4xIiwidXBkYXRlZEluVmVyIjoiNDEuMjMuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 13:19:40 -04:00
Eli Bosley
45bb49bcd6 fix(deps): storybook v9 (#1476)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Upgraded Storybook and related dependencies to the latest major
version.
  * Updated Storybook configuration and removed deprecated addons.
  * Added Storybook linting plugin to the development environment.
* Added deployment scripts and configuration for Storybook to Cloudflare
Workers.
* Introduced GitHub Actions workflow for automated Storybook deployment
to staging and production environments.
* Enhanced environment variable loading to suppress output in production
and non-development environments.

* **Refactor**
* Updated all Storybook stories to use the new Storybook package imports
and consistent single-quote formatting.
* Improved ESLint configuration formatting and included recommended
Storybook linting rules.

* **Style**
* Standardized import statements and string quotes across all Storybook
story files for consistency.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-08 13:00:20 -04:00
renovate[bot]
06578fcdf5 chore(deps): update dependency vue-tsc to v3 (#1473)
This PR contains the following updates:

| Package | Change | Age | Confidence |
|---|---|---|---|
| [vue-tsc](https://redirect.github.com/vuejs/language-tools)
([source](https://redirect.github.com/vuejs/language-tools/tree/HEAD/packages/tsc))
| [`2.2.10` ->
`3.0.1`](https://renovatebot.com/diffs/npm/vue-tsc/2.2.10/3.0.1) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/vue-tsc/3.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/vue-tsc/2.2.10/3.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>vuejs/language-tools (vue-tsc)</summary>

###
[`v3.0.1`](https://redirect.github.com/vuejs/language-tools/blob/HEAD/CHANGELOG.md#301-2025-07-02)

[Compare
Source](https://redirect.github.com/vuejs/language-tools/compare/v3.0.0...v3.0.1)

##### Bug Fixes

- fix(language-core): remove calculation logic of element inner loc
([#&#8203;5460](https://redirect.github.com/vuejs/language-tools/issues/5460))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(vscode): correct syntax highlight of `v-else`
([#&#8203;5470](https://redirect.github.com/vuejs/language-tools/issues/5470))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!

##### Other Changes

- docs(vscode): update Russian translation for VS Code extension
([#&#8203;5461](https://redirect.github.com/vuejs/language-tools/issues/5461))
- Thanks to
[@&#8203;AndreyYolkin](https://redirect.github.com/AndreyYolkin)!
- chore: update volar to 2.4.17
- typescript: correctly use `getModeForUsageLocation` to calculate the
resolution mode

###
[`v3.0.0`](https://redirect.github.com/vuejs/language-tools/blob/HEAD/CHANGELOG.md#300-2025-07-01)

[Compare
Source](https://redirect.github.com/vuejs/language-tools/compare/v2.2.12...v3.0.0)

##### Features

- feat(typescript-plugin): skip declaration files in goto components
definition
([#&#8203;5221](https://redirect.github.com/vuejs/language-tools/issues/5221))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- feat(language-core): introduce `strictVModel` option
([#&#8203;5229](https://redirect.github.com/vuejs/language-tools/issues/5229))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- feat(vscode, language-server, typescript-plugin): communicate with
tsserver based on request forwarding
([#&#8203;5252](https://redirect.github.com/vuejs/language-tools/issues/5252),
[#&#8203;5395](https://redirect.github.com/vuejs/language-tools/issues/5395),
[#&#8203;5443](https://redirect.github.com/vuejs/language-tools/issues/5443))
- feat(language-core): support navigation of events with `v-on` syntax
([#&#8203;5275](https://redirect.github.com/vuejs/language-tools/issues/5275))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- feat(language-core): type support of slot children
([#&#8203;5137](https://redirect.github.com/vuejs/language-tools/issues/5137))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- feat(language-service): autocomplete for props with union type
- feat(language-service): document links for template refs
([#&#8203;5385](https://redirect.github.com/vuejs/language-tools/issues/5385))
- Thanks to
[@&#8203;alex-snezhko](https://redirect.github.com/alex-snezhko)!
- feat(language-core): resolve external stylesheets
([#&#8203;5136](https://redirect.github.com/vuejs/language-tools/issues/5136))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- feat(language-core): add `strictCssModules` option
([#&#8203;5164](https://redirect.github.com/vuejs/language-tools/issues/5164))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- feat(component-type-helpers): add `ComponentAttrs` type for attribute
extraction
- feat(vscode): add support for `typescript.sortImports`,
`typescript.removeUnusedImports` commands
([#&#8203;5444](https://redirect.github.com/vuejs/language-tools/issues/5444))
- feat(vscode): i18n support of configurations and commands with
`zh-CN`, `zh-TW`, `ru` and `ja`
([#&#8203;5330](https://redirect.github.com/vuejs/language-tools/issues/5330),
[#&#8203;5340](https://redirect.github.com/vuejs/language-tools/issues/5340),
[#&#8203;5404](https://redirect.github.com/vuejs/language-tools/issues/5404))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX),
[@&#8203;PurplePlanen](https://redirect.github.com/PurplePlanen) and
[@&#8203;zyoshoka](https://redirect.github.com/zyoshoka)!

##### Bug Fixes

- fix(language-core): generate condition guards for model events
([#&#8203;5225](https://redirect.github.com/vuejs/language-tools/issues/5225))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(language-core): prevent global types generation in declaration
files
([#&#8203;5239](https://redirect.github.com/vuejs/language-tools/issues/5239))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(language-core): prevent eager inference of slot props from
generics
([#&#8203;5247](https://redirect.github.com/vuejs/language-tools/issues/5247))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(typescript-plugin): prevent highlighting native element tags with
same name as components
([#&#8203;5253](https://redirect.github.com/vuejs/language-tools/issues/5253))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(language-service): do not provide required props inlay hints for
intrinsic elements
([#&#8203;5258](https://redirect.github.com/vuejs/language-tools/issues/5258))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(vscode): handle `typescript-language-features` module loading race
condition
([#&#8203;5260](https://redirect.github.com/vuejs/language-tools/issues/5260))
- fix(component-meta): update event type representation to include array
notation
- fix(language-core): correct error mapping when prop exp is arrow
function
([#&#8203;5262](https://redirect.github.com/vuejs/language-tools/issues/5262))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(language-service): add document highlights support
([#&#8203;5263](https://redirect.github.com/vuejs/language-tools/issues/5263))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(language-core): correct type inference of multiple template refs
with same name
([#&#8203;5271](https://redirect.github.com/vuejs/language-tools/issues/5271))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(language-core): skip AST parsing when the expression is an
identifier
([#&#8203;5268](https://redirect.github.com/vuejs/language-tools/issues/5268))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(language-core): do not drop leading comments of `defineModels`
([#&#8203;5273](https://redirect.github.com/vuejs/language-tools/issues/5273))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(language-core): improve fault tolerance for unsupported script
languages
- fix(language-core): avoid invalid auto import edit position when setup
global types fails
- fix(language-core): transform slot parameter list into equivalent
binding pattern
([#&#8203;5245](https://redirect.github.com/vuejs/language-tools/issues/5245))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(language-core): correct codegen when src path does not match the
generated length - Thanks to
[@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(language-service): exclude `data-` attribute completion from sfc
level nodes - Thanks to
[@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(language-core): remove semantic highlight of v-bind shorthand
([#&#8203;5321](https://redirect.github.com/vuejs/language-tools/issues/5321))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(vscode): inline html comment pattern in Vue syntax definition
([#&#8203;5327](https://redirect.github.com/vuejs/language-tools/issues/5327))
- Thanks to [@&#8203;zyoshoka](https://redirect.github.com/zyoshoka)!
- fix(language-core): avoid unrelated virtual code recomputes on style
and template change - Thanks to
[@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(component-meta): attach namespace prefix correctly on generated
types
([#&#8203;5326](https://redirect.github.com/vuejs/language-tools/issues/5326))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(language-core): drop `undefined` from optional prop type with
default in template
([#&#8203;5339](https://redirect.github.com/vuejs/language-tools/issues/5339))
- Thanks to
[@&#8203;Dylancyclone](https://redirect.github.com/Dylancyclone)!
- fix: depend on exact volar version
([#&#8203;5345](https://redirect.github.com/vuejs/language-tools/issues/5345))
- Thanks to
[@&#8203;tomblachut](https://redirect.github.com/tomblachut)!
- fix(language-core): ignore frontmatter block in markdown files
([#&#8203;5362](https://redirect.github.com/vuejs/language-tools/issues/5362))
- Thanks to [@&#8203;brc-dd](https://redirect.github.com/brc-dd)!
- fix(component-meta): only exclude vnode events from props
([#&#8203;5369](https://redirect.github.com/vuejs/language-tools/issues/5369))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(language-core): skip css references for position within virtual
code with `navigation: true`
([#&#8203;5378](https://redirect.github.com/vuejs/language-tools/issues/5378))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(language-core): hoist export declarations from generic script
block
([#&#8203;5398](https://redirect.github.com/vuejs/language-tools/issues/5398))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(vscode): correct syntax highlight for directives starting with
`v-for`
([#&#8203;5399](https://redirect.github.com/vuejs/language-tools/issues/5399))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(language-core): correct support for flatten plugins
([#&#8203;5392](https://redirect.github.com/vuejs/language-tools/issues/5392))
- Thanks to
[@&#8203;zhiyuanzmj](https://redirect.github.com/zhiyuanzmj)!
- fix(language-core): remove `semantic` code feature on first argument
of `useCssModule` and `useTemplateRef` - Thanks to
[@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(typescript-plugin): filter completion items of macros and global
variables in template and styles
([#&#8203;5425](https://redirect.github.com/vuejs/language-tools/issues/5425))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(language-core): do not generate redundant function scopes to
affect type narrowing
([#&#8203;5430](https://redirect.github.com/vuejs/language-tools/issues/5430))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- fix(component-meta): add new file name in `updateFile`
([#&#8203;5438](https://redirect.github.com/vuejs/language-tools/issues/5438))
- Thanks to [@&#8203;Akryum](https://redirect.github.com/Akryum)!
- fix(language-core): `Prettify<T>` breaks generics inferencing
([#&#8203;5424](https://redirect.github.com/vuejs/language-tools/issues/5424))
- Thanks to [@&#8203;so1ve](https://redirect.github.com/so1ve)!
- fix(language-core): use `var` instead of `let` to declare `attrsVar`
that may be hoisted - Thanks to
[@&#8203;KazariEX](https://redirect.github.com/KazariEX)!

##### Performance

- perf(language-core): cache and reuse inline ts asts during full
updates
([#&#8203;5435](https://redirect.github.com/vuejs/language-tools/issues/5435))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!

##### Other Changes

- refactor(vscode, language-server): remove hybrid mode configuration
([#&#8203;5248](https://redirect.github.com/vuejs/language-tools/issues/5248))
- refactor(vscode): remove write virtual files command
- chore(vscode): correct `directory` path in package.json
([#&#8203;5283](https://redirect.github.com/vuejs/language-tools/issues/5283))
- Thanks to [@&#8203;zyoshoka](https://redirect.github.com/zyoshoka)!
- chore(vscode): use rolldown for bundling
([#&#8203;5337](https://redirect.github.com/vuejs/language-tools/issues/5337))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- refactor(vscode): remove doctor - Thanks to
[@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- docs: update instructions for neovim lsp configuration
([#&#8203;5361](https://redirect.github.com/vuejs/language-tools/issues/5361))
- Thanks to [@&#8203;kshksdrt](https://redirect.github.com/kshksdrt)!
- refactor(vscode): remove Vite problem matcher
([#&#8203;5375](https://redirect.github.com/vuejs/language-tools/issues/5375))
- chore(docs): update vue language package name
([#&#8203;5376](https://redirect.github.com/vuejs/language-tools/issues/5376))
- Thanks to [@&#8203;marktlinn](https://redirect.github.com/marktlinn)!
- chore(ci): set pre-release status when publishing to Open VSX
([#&#8203;5377](https://redirect.github.com/vuejs/language-tools/issues/5377))
- Thanks to [@&#8203;lukashass](https://redirect.github.com/lukashass)!
- docs: fallback workaround of `vue_language_server_path` in nvim setup
example
([#&#8203;5391](https://redirect.github.com/vuejs/language-tools/issues/5391))
- Thanks to
[@&#8203;menuRivera](https://redirect.github.com/menuRivera)!
- test(component-meta): simplify code with snapshots
([#&#8203;5403](https://redirect.github.com/vuejs/language-tools/issues/5403))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- docs(nvim): move neovim lspconfig docs to wiki page
([#&#8203;5408](https://redirect.github.com/vuejs/language-tools/issues/5408))
- Thanks to
[@&#8203;RayGuo-ergou](https://redirect.github.com/RayGuo-ergou)!
- refactor(language-server): drop `typescript.tsdk` initialization
option
([#&#8203;5409](https://redirect.github.com/vuejs/language-tools/issues/5409))
- refactor(language-service): drop name casing convertion and its
language status item
([#&#8203;5411](https://redirect.github.com/vuejs/language-tools/issues/5411))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- refactor(language-core): drop `defineProp` support
([#&#8203;5415](https://redirect.github.com/vuejs/language-tools/issues/5415))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- chore(vscode): change display name to "Vue (Official)"
- refactor: cleanup dependencies relationship
([#&#8203;5421](https://redirect.github.com/vuejs/language-tools/issues/5421))
- refactor(component-meta): use type-helpers as a peer dependency
- refactor(vscode): cleanup extension client
([#&#8203;5422](https://redirect.github.com/vuejs/language-tools/issues/5422))
- refactor(language-server): move in server code from insiders edition
([#&#8203;5423](https://redirect.github.com/vuejs/language-tools/issues/5423))
- chore: introduce oxlint for faster linting
([#&#8203;5416](https://redirect.github.com/vuejs/language-tools/issues/5416))
- Thanks to [@&#8203;KazariEX](https://redirect.github.com/KazariEX)!
- refactor(vscode): remove split editor feature
([#&#8203;5446](https://redirect.github.com/vuejs/language-tools/issues/5446))
- refactor(vscode): rename configuration keys from `complete` to
`suggest` for clarity

###
[`v2.2.12`](https://redirect.github.com/vuejs/language-tools/compare/v2.2.10...0b13bf1966398ea3949b6b02d09b251ddc9a51eb)

[Compare
Source](https://redirect.github.com/vuejs/language-tools/compare/v2.2.10...v2.2.12)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNy4yIiwidXBkYXRlZEluVmVyIjoiNDEuMjMuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 11:57:14 -04:00
Eli Bosley
e791cc680d fix: header padding regression (#1477)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Style**
* Improved spacing in the header and user profile components by adding
top and right margins for a cleaner layout.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-08 11:55:45 -04:00
renovate[bot]
5ce5d19db0 chore(deps): pin node.js (#1469)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [node](https://redirect.github.com/nodejs/node) | final | pin |
`22-bookworm-slim` -> `22.17.0-bookworm-slim` |

Add the preset `:preserveSemverRanges` to your config if you don't want
to pin your dependencies.

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNy4yIiwidXBkYXRlZEluVmVyIjoiNDEuMTcuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 11:34:49 -04:00
Eli Bosley
c0ccdfa030 chore: replace standard-version with commit-and-tag-version 2025-07-08 11:08:07 -04:00
renovate[bot]
d613bfa041 fix(deps): update dependency dotenv to v17 (#1474)
This PR contains the following updates:

| Package | Change | Age | Confidence |
|---|---|---|---|
| [dotenv](https://redirect.github.com/motdotla/dotenv) | [`16.5.0` ->
`17.1.0`](https://renovatebot.com/diffs/npm/dotenv/16.5.0/17.1.0) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/dotenv/17.1.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/dotenv/16.5.0/17.1.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>motdotla/dotenv (dotenv)</summary>

###
[`v17.1.0`](https://redirect.github.com/motdotla/dotenv/blob/HEAD/CHANGELOG.md#1710-2025-07-07)

[Compare
Source](https://redirect.github.com/motdotla/dotenv/compare/v17.0.1...v17.1.0)

##### Added

- Add additional security and configuration tips to the runtime log
([#&#8203;884](https://redirect.github.com/motdotla/dotenv/pull/884))
- Dim the tips text from the main injection information text

```js
const TIPS = [
  '🔐 encrypt with dotenvx: https://dotenvx.com',
  '🔐 prevent committing .env to code: https://dotenvx.com/precommit',
  '🔐 prevent building .env in docker: https://dotenvx.com/prebuild',
  '🛠️  run anywhere with `dotenvx run -- yourcommand`',
  '⚙️  specify custom .env file path with { path: \'/custom/path/.env\' }',
  '⚙️  enable debug logging with { debug: true }',
  '⚙️  override existing env vars with { override: true }',
  '⚙️  suppress all logs with { quiet: true }',
  '⚙️  write to custom object with { processEnv: myObject }',
  '⚙️  load multiple .env files with { path: [\'.env.local\', \'.env\'] }'
]
```

###
[`v17.0.1`](https://redirect.github.com/motdotla/dotenv/blob/HEAD/CHANGELOG.md#1701-2025-07-01)

[Compare
Source](https://redirect.github.com/motdotla/dotenv/compare/v17.0.0...v17.0.1)

##### Changed

- Patched injected log to count only populated/set keys to process.env
([#&#8203;879](https://redirect.github.com/motdotla/dotenv/pull/879))

###
[`v17.0.0`](https://redirect.github.com/motdotla/dotenv/blob/HEAD/CHANGELOG.md#1700-2025-06-27)

[Compare
Source](https://redirect.github.com/motdotla/dotenv/compare/v16.6.1...v17.0.0)

##### Changed

- Default `quiet` to false - informational (file and keys count) runtime
log message shows by default
([#&#8203;875](https://redirect.github.com/motdotla/dotenv/pull/874))

###
[`v16.6.1`](https://redirect.github.com/motdotla/dotenv/blob/HEAD/CHANGELOG.md#1661-2025-06-27)

[Compare
Source](https://redirect.github.com/motdotla/dotenv/compare/v16.6.0...v16.6.1)

##### Changed

- Default `quiet` to true – hiding the runtime log message
([#&#8203;874](https://redirect.github.com/motdotla/dotenv/pull/874))
- NOTICE: 17.0.0 will be released with quiet defaulting to false. Use
`config({ quiet: true })` to suppress.
- And check out the new
[dotenvx](https://redirect.github.com/dotenvx/dotenvx). As coding
workflows evolve and agents increasingly handle secrets, encrypted .env
files offer a much safer way to deploy both agents and code together
with secure secrets. Simply switch `require('dotenv').config()` for
`require('@&#8203;dotenvx/dotenvx').config()`.

###
[`v16.6.0`](https://redirect.github.com/motdotla/dotenv/blob/HEAD/CHANGELOG.md#1660-2025-06-26)

[Compare
Source](https://redirect.github.com/motdotla/dotenv/compare/v16.5.0...v16.6.0)

##### Added

- Default log helpful message `[dotenv@16.6.0] injecting env (1) from
.env`
([#&#8203;870](https://redirect.github.com/motdotla/dotenv/pull/870))
- Use `{ quiet: true }` to suppress
- Aligns dotenv more closely with
[dotenvx](https://redirect.github.com/dotenvx/dotenvx).

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNy4yIiwidXBkYXRlZEluVmVyIjoiNDEuMjMuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 10:59:03 -04:00
renovate[bot]
453a5b2c95 fix(deps): update dependency marked to v16 (#1444)
This PR contains the following updates:

| Package | Change | Age | Confidence |
|---|---|---|---|
| [marked](https://marked.js.org)
([source](https://redirect.github.com/markedjs/marked)) | [`15.0.12` ->
`16.0.0`](https://renovatebot.com/diffs/npm/marked/15.0.12/16.0.0) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/marked/16.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/marked/15.0.12/16.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>markedjs/marked (marked)</summary>

###
[`v16.0.0`](https://redirect.github.com/markedjs/marked/releases/tag/v16.0.0)

[Compare
Source](https://redirect.github.com/markedjs/marked/compare/v15.0.12...v16.0.0)

##### Bug Fixes

- remove cjs build & update min node to 20
([#&#8203;3687](https://redirect.github.com/markedjs/marked/issues/3687))
([0a35d8f](0a35d8f28b))

##### BREAKING CHANGES

- minify ./lib/marked.esm.js and ./lib/marked.umd.js
- remove ./marked.min.js use ./lib/marked.umd.js instead
- remove ./lib/marked.cjs
- update minimum supported node version to 20 to support
`require('marked.esm.js')`. see
https://nodejs.org/docs/latest-v20.x/api/modules.html#loading-ecmascript-modules-using-require

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC42Mi4xIiwidXBkYXRlZEluVmVyIjoiNDEuMjMuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 10:55:28 -04:00
renovate[bot]
8a82a3a1b7 chore(deps): update dependency vite-plugin-node to v7 (#1471)
This PR contains the following updates:

| Package | Change | Age | Confidence |
|---|---|---|---|
|
[vite-plugin-node](https://redirect.github.com/axe-me/vite-plugin-node)
| [`5.0.1` ->
`7.0.0`](https://renovatebot.com/diffs/npm/vite-plugin-node/5.0.1/7.0.0)
|
[![age](https://developer.mend.io/api/mc/badges/age/npm/vite-plugin-node/7.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/vite-plugin-node/5.0.1/7.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>axe-me/vite-plugin-node (vite-plugin-node)</summary>

###
[`v7.0.0`](https://redirect.github.com/axe-me/vite-plugin-node/blob/HEAD/CHANGELOG.md#700)

- support vite 7.x, in order to align with vite major version, the major
version of this plugin is bumped to 7.x as well. rip 6
- add `reloadAppOnFileChange` option, when set to true, the app will be
reloaded on file changes.

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNy4yIiwidXBkYXRlZEluVmVyIjoiNDEuMjMuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 10:48:33 -04:00
Eli Bosley
9b85e009b8 fix: console hidden 2025-07-08 10:46:44 -04:00
Eli Bosley
a87d455bac fix: drop console with terser 2025-07-08 10:46:35 -04:00
renovate[bot]
412b32996d fix(deps): pin dependencies (#1470)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [@apollo/client](https://www.apollographql.com/docs/react/)
([source](https://redirect.github.com/apollographql/apollo-client)) |
dependencies | pin | [`^3.12.3` ->
`3.13.8`](https://renovatebot.com/diffs/npm/@apollo%2fclient/3.13.8/3.13.8)
|
| [@apollo/client](https://www.apollographql.com/docs/react/)
([source](https://redirect.github.com/apollographql/apollo-client)) |
peerDependencies | pin | [`^3.11.8` ->
`3.13.8`](https://renovatebot.com/diffs/npm/@apollo%2fclient/3.13.8/3.13.8)
|
| [@apollo/client](https://www.apollographql.com/docs/react/)
([source](https://redirect.github.com/apollographql/apollo-client)) |
devDependencies | pin | [`^3.11.8` ->
`3.13.8`](https://renovatebot.com/diffs/npm/@apollo%2fclient/3.13.8/3.13.8)
|
| [@apollo/client](https://www.apollographql.com/docs/react/)
([source](https://redirect.github.com/apollographql/apollo-client)) |
dependencies | pin | [`^3.11.8` ->
`3.13.8`](https://renovatebot.com/diffs/npm/@apollo%2fclient/3.13.8/3.13.8)
|
|
[@apollo/server](https://redirect.github.com/apollographql/apollo-server)
([source](https://redirect.github.com/apollographql/apollo-server/tree/HEAD/packages/server))
| dependencies | pin | [`^4.11.2` ->
`4.12.2`](https://renovatebot.com/diffs/npm/@apollo%2fserver/4.12.2/4.12.2)
|
|
[graphql-subscriptions](https://redirect.github.com/apollographql/graphql-subscriptions)
| peerDependencies | pin | [`^3.0.0` ->
`3.0.0`](https://renovatebot.com/diffs/npm/graphql-subscriptions/3.0.0/3.0.0)
|
|
[graphql-subscriptions](https://redirect.github.com/apollographql/graphql-subscriptions)
| devDependencies | pin | [`^3.0.0` ->
`3.0.0`](https://renovatebot.com/diffs/npm/graphql-subscriptions/3.0.0/3.0.0)
|
|
[graphql-subscriptions](https://redirect.github.com/apollographql/graphql-subscriptions)
| dependencies | pin | [`^3.0.0` ->
`3.0.0`](https://renovatebot.com/diffs/npm/graphql-subscriptions/3.0.0/3.0.0)
|
| [graphql-tag](https://redirect.github.com/apollographql/graphql-tag) |
dependencies | pin | [`^2.12.6` ->
`2.12.6`](https://renovatebot.com/diffs/npm/graphql-tag/2.12.6/2.12.6) |
|
[zen-observable-ts](https://redirect.github.com/apollographql/zen-observable-ts)
| peerDependencies | pin | [`^1.1.0` ->
`1.1.0`](https://renovatebot.com/diffs/npm/zen-observable-ts/1.1.0/1.1.0)
|
|
[zen-observable-ts](https://redirect.github.com/apollographql/zen-observable-ts)
| devDependencies | pin | [`^1.1.0` ->
`1.1.0`](https://renovatebot.com/diffs/npm/zen-observable-ts/1.1.0/1.1.0)
|
|
[zen-observable-ts](https://redirect.github.com/apollographql/zen-observable-ts)
| dependencies | pin | [`^1.1.0` ->
`1.1.0`](https://renovatebot.com/diffs/npm/zen-observable-ts/1.1.0/1.1.0)
|

Add the preset `:preserveSemverRanges` to your config if you don't want
to pin your dependencies.

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNy4yIiwidXBkYXRlZEluVmVyIjoiNDEuMTcuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 10:44:39 -04:00
renovate[bot]
ba75a409a4 fix(deps): pin dependencies (#1465)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[@as-integrations/fastify](https://redirect.github.com/apollo-server-integrations/apollo-server-integration-fastify/blob/main/readme.md)
([source](https://redirect.github.com/apollo-server-integrations/apollo-server-integration-fastify))
| dependencies | pin | [`^2.1.1` ->
`2.1.1`](https://renovatebot.com/diffs/npm/@as-integrations%2ffastify/2.1.1/2.1.1)
|
| [@eslint/js](https://eslint.org)
([source](https://redirect.github.com/eslint/eslint/tree/HEAD/packages/js))
| devDependencies | pin | [`^9.21.0` ->
`9.29.0`](https://renovatebot.com/diffs/npm/@eslint%2fjs/9.29.0/9.29.0)
|
| [@faker-js/faker](https://fakerjs.dev)
([source](https://redirect.github.com/faker-js/faker)) | devDependencies
| pin | [`^9.8.0` ->
`9.8.0`](https://renovatebot.com/diffs/npm/@faker-js%2ffaker/9.8.0/9.8.0)
|
| [@fastify/cookie](https://redirect.github.com/fastify/fastify-cookie)
| dependencies | pin | [`^11.0.2` ->
`11.0.2`](https://renovatebot.com/diffs/npm/@fastify%2fcookie/11.0.2/11.0.2)
|
| [@fastify/helmet](https://redirect.github.com/fastify/fastify-helmet)
| dependencies | pin | [`^13.0.1` ->
`13.0.1`](https://renovatebot.com/diffs/npm/@fastify%2fhelmet/13.0.1/13.0.1)
|
| [@floating-ui/dom](https://floating-ui.com)
([source](https://redirect.github.com/floating-ui/floating-ui/tree/HEAD/packages/dom))
| dependencies | pin | [`^1.6.12` ->
`1.7.1`](https://renovatebot.com/diffs/npm/@floating-ui%2fdom/1.7.1/1.7.1)
|
| [@floating-ui/utils](https://floating-ui.com)
([source](https://redirect.github.com/floating-ui/floating-ui/tree/HEAD/packages/utils))
| dependencies | pin | [`^0.2.8` ->
`0.2.9`](https://renovatebot.com/diffs/npm/@floating-ui%2futils/0.2.9/0.2.9)
|
| [@floating-ui/vue](https://floating-ui.com/docs/vue)
([source](https://redirect.github.com/floating-ui/floating-ui/tree/HEAD/packages/vue))
| dependencies | pin | [`^1.1.5` ->
`1.1.6`](https://renovatebot.com/diffs/npm/@floating-ui%2fvue/1.1.6/1.1.6)
|
|
[@graphql-codegen/add](https://redirect.github.com/dotansimha/graphql-code-generator)
([source](https://redirect.github.com/dotansimha/graphql-code-generator/tree/HEAD/packages/plugins/other/add))
| devDependencies | pin | [`^5.0.3` ->
`5.0.3`](https://renovatebot.com/diffs/npm/@graphql-codegen%2fadd/5.0.3/5.0.3)
|
|
[@graphql-codegen/cli](https://redirect.github.com/dotansimha/graphql-code-generator)
([source](https://redirect.github.com/dotansimha/graphql-code-generator/tree/HEAD/packages/graphql-codegen-cli))
| devDependencies | pin | [`^5.0.3` ->
`5.0.7`](https://renovatebot.com/diffs/npm/@graphql-codegen%2fcli/5.0.7/5.0.7)
|
|
[@graphql-codegen/client-preset](https://redirect.github.com/dotansimha/graphql-code-generator)
([source](https://redirect.github.com/dotansimha/graphql-code-generator/tree/HEAD/packages/presets/client))
| devDependencies | pin | [`^4.5.1` ->
`4.8.2`](https://renovatebot.com/diffs/npm/@graphql-codegen%2fclient-preset/4.8.2/4.8.2)
|
|
[@graphql-codegen/client-preset](https://redirect.github.com/dotansimha/graphql-code-generator)
([source](https://redirect.github.com/dotansimha/graphql-code-generator/tree/HEAD/packages/presets/client))
| dependencies | pin | [`^4.5.0` ->
`4.8.2`](https://renovatebot.com/diffs/npm/@graphql-codegen%2fclient-preset/4.8.2/4.8.2)
|
|
[@graphql-codegen/fragment-matcher](https://redirect.github.com/dotansimha/graphql-code-generator)
([source](https://redirect.github.com/dotansimha/graphql-code-generator/tree/HEAD/packages/plugins/other/fragment-matcher))
| devDependencies | pin | [`^5.0.2` ->
`5.1.0`](https://renovatebot.com/diffs/npm/@graphql-codegen%2ffragment-matcher/5.1.0/5.1.0)
|
|
[@graphql-codegen/import-types-preset](https://redirect.github.com/dotansimha/graphql-code-generator-community)
([source](https://redirect.github.com/dotansimha/graphql-code-generator-community/tree/HEAD/packages/presets/import-types))
| devDependencies | pin | [`^3.0.0` ->
`3.0.1`](https://renovatebot.com/diffs/npm/@graphql-codegen%2fimport-types-preset/3.0.1/3.0.1)
|
|
[@graphql-codegen/introspection](https://redirect.github.com/dotansimha/graphql-code-generator)
([source](https://redirect.github.com/dotansimha/graphql-code-generator/tree/HEAD/packages/plugins/other/introspection))
| devDependencies | pin | [`^4.0.3` ->
`4.0.3`](https://renovatebot.com/diffs/npm/@graphql-codegen%2fintrospection/4.0.3/4.0.3)
|
|
[@graphql-codegen/typed-document-node](https://redirect.github.com/dotansimha/graphql-code-generator)
([source](https://redirect.github.com/dotansimha/graphql-code-generator/tree/HEAD/packages/plugins/typescript/typed-document-node))
| devDependencies | pin | [`^5.0.11` ->
`5.1.1`](https://renovatebot.com/diffs/npm/@graphql-codegen%2ftyped-document-node/5.1.1/5.1.1)
|
|
[@graphql-codegen/typescript](https://redirect.github.com/dotansimha/graphql-code-generator)
([source](https://redirect.github.com/dotansimha/graphql-code-generator/tree/HEAD/packages/plugins/typescript/typescript))
| devDependencies | pin | [`^4.1.1` ->
`4.1.6`](https://renovatebot.com/diffs/npm/@graphql-codegen%2ftypescript/4.1.6/4.1.6)
|
|
[@graphql-codegen/typescript-operations](https://redirect.github.com/dotansimha/graphql-code-generator)
([source](https://redirect.github.com/dotansimha/graphql-code-generator/tree/HEAD/packages/plugins/typescript/operations))
| devDependencies | pin | [`^4.3.1` ->
`4.6.1`](https://renovatebot.com/diffs/npm/@graphql-codegen%2ftypescript-operations/4.6.1/4.6.1)
|
|
[@graphql-tools/load-files](https://redirect.github.com/ardatan/graphql-tools)
([source](https://redirect.github.com/ardatan/graphql-tools/tree/HEAD/packages/load-files))
| dependencies | pin | [`^7.0.0` ->
`7.0.1`](https://renovatebot.com/diffs/npm/@graphql-tools%2fload-files/7.0.1/7.0.1)
|
|
[@graphql-tools/merge](https://redirect.github.com/ardatan/graphql-tools)
([source](https://redirect.github.com/ardatan/graphql-tools/tree/HEAD/packages/merge))
| dependencies | pin | [`^9.0.8` ->
`9.0.24`](https://renovatebot.com/diffs/npm/@graphql-tools%2fmerge/9.0.24/9.0.24)
|
|
[@graphql-tools/schema](https://redirect.github.com/ardatan/graphql-tools)
([source](https://redirect.github.com/ardatan/graphql-tools/tree/HEAD/packages/schema))
| dependencies | pin | [`^10.0.7` ->
`10.0.23`](https://renovatebot.com/diffs/npm/@graphql-tools%2fschema/10.0.23/10.0.23)
|
|
[@graphql-tools/utils](https://redirect.github.com/ardatan/graphql-tools)
([source](https://redirect.github.com/ardatan/graphql-tools/tree/HEAD/packages/utils))
| peerDependencies | pin | [`^10.5.5` ->
`10.8.6`](https://renovatebot.com/diffs/npm/@graphql-tools%2futils/10.8.6/10.8.6)
|
|
[@graphql-tools/utils](https://redirect.github.com/ardatan/graphql-tools)
([source](https://redirect.github.com/ardatan/graphql-tools/tree/HEAD/packages/utils))
| devDependencies | pin | [`^10.5.5` ->
`10.8.6`](https://renovatebot.com/diffs/npm/@graphql-tools%2futils/10.8.6/10.8.6)
|
|
[@graphql-tools/utils](https://redirect.github.com/ardatan/graphql-tools)
([source](https://redirect.github.com/ardatan/graphql-tools/tree/HEAD/packages/utils))
| dependencies | pin | [`^10.5.5` ->
`10.8.6`](https://renovatebot.com/diffs/npm/@graphql-tools%2futils/10.8.6/10.8.6)
|
|
[@graphql-typed-document-node/core](https://redirect.github.com/dotansimha/graphql-typed-document-node)
| devDependencies | pin | [`^3.2.0` ->
`3.2.0`](https://renovatebot.com/diffs/npm/@graphql-typed-document-node%2fcore/3.2.0/3.2.0)
|
|
[@graphql-typed-document-node/core](https://redirect.github.com/dotansimha/graphql-typed-document-node)
| peerDependencies | pin | [`^3.2.0` ->
`3.2.0`](https://renovatebot.com/diffs/npm/@graphql-typed-document-node%2fcore/3.2.0/3.2.0)
|
| [@headlessui/vue](https://redirect.github.com/tailwindlabs/headlessui)
([source](https://redirect.github.com/tailwindlabs/headlessui/tree/HEAD/packages/@headlessui-vue))
| dependencies | pin | [`^1.7.23` ->
`1.7.23`](https://renovatebot.com/diffs/npm/@headlessui%2fvue/1.7.23/1.7.23)
|
| [@heroicons/vue](https://redirect.github.com/tailwindlabs/heroicons) |
dependencies | pin | [`^2.2.0` ->
`2.2.0`](https://renovatebot.com/diffs/npm/@heroicons%2fvue/2.2.0/2.2.0)
|
|
[@ianvs/prettier-plugin-sort-imports](https://redirect.github.com/ianvs/prettier-plugin-sort-imports)
| devDependencies | pin | [`^4.4.0` ->
`4.4.2`](https://renovatebot.com/diffs/npm/@ianvs%2fprettier-plugin-sort-imports/4.4.2/4.4.2)
|
|
[@ianvs/prettier-plugin-sort-imports](https://redirect.github.com/ianvs/prettier-plugin-sort-imports)
| devDependencies | pin | [`^4.4.1` ->
`4.4.2`](https://renovatebot.com/diffs/npm/@ianvs%2fprettier-plugin-sort-imports/4.4.2/4.4.2)
|
|
[@internationalized/number](https://redirect.github.com/adobe/react-spectrum)
| dependencies | pin | [`^3.6.0` ->
`3.6.3`](https://renovatebot.com/diffs/npm/@internationalized%2fnumber/3.6.3/3.6.3)
|
| [@jsonforms/core](http://jsonforms.io/)
([source](https://redirect.github.com/eclipsesource/jsonforms)) |
dependencies | pin | [`^3.6.0` ->
`3.6.0`](https://renovatebot.com/diffs/npm/@jsonforms%2fcore/3.6.0/3.6.0)
|
| [@jsonforms/core](http://jsonforms.io/)
([source](https://redirect.github.com/eclipsesource/jsonforms)) |
peerDependencies | pin | [`^3.5.1` ->
`3.6.0`](https://renovatebot.com/diffs/npm/@jsonforms%2fcore/3.6.0/3.6.0)
|
| [@jsonforms/core](http://jsonforms.io/)
([source](https://redirect.github.com/eclipsesource/jsonforms)) |
devDependencies | pin | [`^3.5.1` ->
`3.6.0`](https://renovatebot.com/diffs/npm/@jsonforms%2fcore/3.6.0/3.6.0)
|
| [@jsonforms/core](http://jsonforms.io/)
([source](https://redirect.github.com/eclipsesource/jsonforms)) |
dependencies | pin | [`^3.5.1` ->
`3.6.0`](https://renovatebot.com/diffs/npm/@jsonforms%2fcore/3.6.0/3.6.0)
|
| [@jsonforms/vue](http://jsonforms.io/)
([source](https://redirect.github.com/eclipsesource/jsonforms)) |
dependencies | pin | [`^3.6.0` ->
`3.6.0`](https://renovatebot.com/diffs/npm/@jsonforms%2fvue/3.6.0/3.6.0)
|
| [@jsonforms/vue-vanilla](http://jsonforms.io/)
([source](https://redirect.github.com/eclipsesource/jsonforms)) |
dependencies | pin | [`^3.6.0` ->
`3.6.0`](https://renovatebot.com/diffs/npm/@jsonforms%2fvue-vanilla/3.6.0/3.6.0)
|
| [@jsonforms/vue-vuetify](http://jsonforms.io/)
([source](https://redirect.github.com/eclipsesource/jsonforms)) |
dependencies | pin | [`^3.6.0` ->
`3.6.0`](https://renovatebot.com/diffs/npm/@jsonforms%2fvue-vuetify/3.6.0/3.6.0)
|
| [@manypkg/cli](https://redirect.github.com/Thinkmill/manypkg)
([source](https://redirect.github.com/Thinkmill/manypkg/tree/HEAD/packages/cli))
| dependencies | pin | [`^0.24.0` ->
`0.24.0`](https://renovatebot.com/diffs/npm/@manypkg%2fcli/0.24.0/0.24.0)
|
| [@nestjs/apollo](https://redirect.github.com/nestjs/graphql) |
peerDependencies | pin | [`^13.0.3` ->
`13.1.0`](https://renovatebot.com/diffs/npm/@nestjs%2fapollo/13.1.0/13.1.0)
|
| [@nestjs/apollo](https://redirect.github.com/nestjs/graphql) |
devDependencies | pin | [`^13.0.3` ->
`13.1.0`](https://renovatebot.com/diffs/npm/@nestjs%2fapollo/13.1.0/13.1.0)
|
| [@nestjs/apollo](https://redirect.github.com/nestjs/graphql) |
dependencies | pin | [`^13.0.3` ->
`13.1.0`](https://renovatebot.com/diffs/npm/@nestjs%2fapollo/13.1.0/13.1.0)
|
|
[@nestjs/cache-manager](https://redirect.github.com/nestjs/cache-manager)
| dependencies | pin | [`^3.0.1` ->
`3.0.1`](https://renovatebot.com/diffs/npm/@nestjs%2fcache-manager/3.0.1/3.0.1)
|
| [@nestjs/common](https://nestjs.com)
([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/common))
| peerDependencies | pin | [`^11.0.11` ->
`11.1.3`](https://renovatebot.com/diffs/npm/@nestjs%2fcommon/11.1.3/11.1.3)
|
| [@nestjs/common](https://nestjs.com)
([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/common))
| devDependencies | pin | [`^11.0.11` ->
`11.1.3`](https://renovatebot.com/diffs/npm/@nestjs%2fcommon/11.1.3/11.1.3)
|
| [@nestjs/common](https://nestjs.com)
([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/common))
| dependencies | pin | [`^11.0.11` ->
`11.1.3`](https://renovatebot.com/diffs/npm/@nestjs%2fcommon/11.1.3/11.1.3)
|
| [@nestjs/config](https://redirect.github.com/nestjs/config) |
peerDependencies | pin | [`^4.0.2` ->
`4.0.2`](https://renovatebot.com/diffs/npm/@nestjs%2fconfig/4.0.2/4.0.2)
|
| [@nestjs/config](https://redirect.github.com/nestjs/config) |
devDependencies | pin | [`^4.0.2` ->
`4.0.2`](https://renovatebot.com/diffs/npm/@nestjs%2fconfig/4.0.2/4.0.2)
|
| [@nestjs/config](https://redirect.github.com/nestjs/config) |
dependencies | pin | [`^4.0.2` ->
`4.0.2`](https://renovatebot.com/diffs/npm/@nestjs%2fconfig/4.0.2/4.0.2)
|
| [@nestjs/core](https://nestjs.com)
([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/core))
| peerDependencies | pin | [`^11.0.11` ->
`11.1.3`](https://renovatebot.com/diffs/npm/@nestjs%2fcore/11.1.3/11.1.3)
|
| [@nestjs/core](https://nestjs.com)
([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/core))
| devDependencies | pin | [`^11.0.11` ->
`11.1.3`](https://renovatebot.com/diffs/npm/@nestjs%2fcore/11.1.3/11.1.3)
|
| [@nestjs/core](https://nestjs.com)
([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/core))
| dependencies | pin | [`^11.0.11` ->
`11.1.3`](https://renovatebot.com/diffs/npm/@nestjs%2fcore/11.1.3/11.1.3)
|
|
[@nestjs/event-emitter](https://redirect.github.com/nestjs/event-emitter)
| peerDependencies | pin | [`^3.0.1` ->
`3.0.1`](https://renovatebot.com/diffs/npm/@nestjs%2fevent-emitter/3.0.1/3.0.1)
|
|
[@nestjs/event-emitter](https://redirect.github.com/nestjs/event-emitter)
| devDependencies | pin | [`^3.0.1` ->
`3.0.1`](https://renovatebot.com/diffs/npm/@nestjs%2fevent-emitter/3.0.1/3.0.1)
|
|
[@nestjs/event-emitter](https://redirect.github.com/nestjs/event-emitter)
| dependencies | pin | [`^3.0.1` ->
`3.0.1`](https://renovatebot.com/diffs/npm/@nestjs%2fevent-emitter/3.0.1/3.0.1)
|
| [@nestjs/graphql](https://redirect.github.com/nestjs/graphql) |
peerDependencies | pin | [`^13.0.3` ->
`13.1.0`](https://renovatebot.com/diffs/npm/@nestjs%2fgraphql/13.1.0/13.1.0)
|
| [@nestjs/graphql](https://redirect.github.com/nestjs/graphql) |
devDependencies | pin | [`^13.0.3` ->
`13.1.0`](https://renovatebot.com/diffs/npm/@nestjs%2fgraphql/13.1.0/13.1.0)
|
| [@nestjs/graphql](https://redirect.github.com/nestjs/graphql) |
dependencies | pin | [`^13.0.3` ->
`13.1.0`](https://renovatebot.com/diffs/npm/@nestjs%2fgraphql/13.1.0/13.1.0)
|
| [@nestjs/passport](https://redirect.github.com/nestjs/passport) |
dependencies | pin | [`^11.0.0` ->
`11.0.5`](https://renovatebot.com/diffs/npm/@nestjs%2fpassport/11.0.5/11.0.5)
|
| [@nestjs/platform-fastify](https://nestjs.com)
([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/platform-fastify))
| dependencies | pin | [`^11.0.11` ->
`11.1.3`](https://renovatebot.com/diffs/npm/@nestjs%2fplatform-fastify/11.1.3/11.1.3)
|
| [@nestjs/schedule](https://redirect.github.com/nestjs/schedule) |
peerDependencies | pin | [`^6.0.0` ->
`6.0.0`](https://renovatebot.com/diffs/npm/@nestjs%2fschedule/6.0.0/6.0.0)
|
| [@nestjs/schedule](https://redirect.github.com/nestjs/schedule) |
devDependencies | pin | [`^6.0.0` ->
`6.0.0`](https://renovatebot.com/diffs/npm/@nestjs%2fschedule/6.0.0/6.0.0)
|
| [@nestjs/schedule](https://redirect.github.com/nestjs/schedule) |
dependencies | pin | [`^6.0.0` ->
`6.0.0`](https://renovatebot.com/diffs/npm/@nestjs%2fschedule/6.0.0/6.0.0)
|
| [@nestjs/testing](https://nestjs.com)
([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/testing))
| devDependencies | pin | [`^11.0.11` ->
`11.1.3`](https://renovatebot.com/diffs/npm/@nestjs%2ftesting/11.1.3/11.1.3)
|
| [@nestjs/throttler](https://redirect.github.com/nestjs/throttler) |
dependencies | pin | [`^6.4.0` ->
`6.4.0`](https://renovatebot.com/diffs/npm/@nestjs%2fthrottler/6.4.0/6.4.0)
|
| [@nuxt/devtools](https://devtools.nuxt.com)
([source](https://redirect.github.com/nuxt/devtools/tree/HEAD/packages/devtools))
| devDependencies | pin | [`^2.0.0` ->
`2.5.0`](https://renovatebot.com/diffs/npm/@nuxt%2fdevtools/2.5.0/2.5.0)
|
| [@nuxt/eslint](https://redirect.github.com/nuxt/eslint)
([source](https://redirect.github.com/nuxt/eslint/tree/HEAD/packages/module))
| devDependencies | pin | [`^1.0.0` ->
`1.4.1`](https://renovatebot.com/diffs/npm/@nuxt%2feslint/1.4.1/1.4.1) |
| [@nuxt/test-utils](https://redirect.github.com/nuxt/test-utils) |
devDependencies | pin | [`^3.17.2` ->
`3.19.1`](https://renovatebot.com/diffs/npm/@nuxt%2ftest-utils/3.19.1/3.19.1)
|
|
[@nuxtjs/color-mode](https://redirect.github.com/nuxt-modules/color-mode)
| dependencies | pin | [`^3.5.2` ->
`3.5.2`](https://renovatebot.com/diffs/npm/@nuxtjs%2fcolor-mode/3.5.2/3.5.2)
|
|
[@nuxtjs/tailwindcss](https://redirect.github.com/nuxt-modules/tailwindcss)
| devDependencies | pin | [`^6.12.2` ->
`6.14.0`](https://renovatebot.com/diffs/npm/@nuxtjs%2ftailwindcss/6.14.0/6.14.0)
|
|
[@originjs/vite-plugin-commonjs](https://redirect.github.com/originjs/vite-plugins/tree/main/packages/vite-plugin-commonjs)
([source](https://redirect.github.com/originjs/vite-plugins)) |
devDependencies | pin | [`^1.0.3` ->
`1.0.3`](https://renovatebot.com/diffs/npm/@originjs%2fvite-plugin-commonjs/1.0.3/1.0.3)
|
| [@pinia/nuxt](https://pinia.vuejs.org/ssr/nuxt.html)
([source](https://redirect.github.com/vuejs/pinia)) | dependencies | pin
| [`^0.11.0` ->
`0.11.1`](https://renovatebot.com/diffs/npm/@pinia%2fnuxt/0.11.1/0.11.1)
|
| [@pinia/testing](https://pinia.vuejs.org/cookbook/testing.html)
([source](https://redirect.github.com/vuejs/pinia)) | devDependencies |
pin | [`^1.0.0` ->
`1.0.2`](https://renovatebot.com/diffs/npm/@pinia%2ftesting/1.0.2/1.0.2)
|
| [@reduxjs/toolkit](https://redux-toolkit.js.org)
([source](https://redirect.github.com/reduxjs/redux-toolkit)) |
dependencies | pin | [`^2.3.0` ->
`2.8.2`](https://renovatebot.com/diffs/npm/@reduxjs%2ftoolkit/2.8.2/2.8.2)
|
|
[@rollup/plugin-node-resolve](https://redirect.github.com/rollup/plugins/tree/master/packages/node-resolve/#readme)
([source](https://redirect.github.com/rollup/plugins/tree/HEAD/packages/node-resolve))
| devDependencies | pin | [`^16.0.0` ->
`16.0.1`](https://renovatebot.com/diffs/npm/@rollup%2fplugin-node-resolve/16.0.1/16.0.1)
|
|
[@rollup/plugin-strip](https://redirect.github.com/rollup/plugins/tree/master/packages/strip#readme)
([source](https://redirect.github.com/rollup/plugins/tree/HEAD/packages/strip))
| devDependencies | pin | [`^3.0.4` ->
`3.0.4`](https://renovatebot.com/diffs/npm/@rollup%2fplugin-strip/3.0.4/3.0.4)
|
| [@rollup/rollup-linux-x64-gnu](https://rollupjs.org/)
([source](https://redirect.github.com/rollup/rollup)) |
optionalDependencies | pin | [`^4.30.1` ->
`4.44.0`](https://renovatebot.com/diffs/npm/@rollup%2frollup-linux-x64-gnu/4.44.0/4.44.0)
|
| [@runonflux/nat-upnp](https://redirect.github.com/runonflux/nat-upnp)
| peerDependencies | pin | [`^1.0.2` ->
`1.0.2`](https://renovatebot.com/diffs/npm/@runonflux%2fnat-upnp/1.0.2/1.0.2)
|
| [@runonflux/nat-upnp](https://redirect.github.com/runonflux/nat-upnp)
| devDependencies | pin | [`^1.0.2` ->
`1.0.2`](https://renovatebot.com/diffs/npm/@runonflux%2fnat-upnp/1.0.2/1.0.2)
|
| [@runonflux/nat-upnp](https://redirect.github.com/runonflux/nat-upnp)
| dependencies | pin | [`^1.0.2` ->
`1.0.2`](https://renovatebot.com/diffs/npm/@runonflux%2fnat-upnp/1.0.2/1.0.2)
|
|
[@storybook/addon-essentials](https://redirect.github.com/storybookjs/storybook/tree/next/code/addons/essentials)
([source](https://redirect.github.com/storybookjs/storybook/tree/HEAD/code/addons/essentials))
| devDependencies | pin | [`^8.6.12` ->
`8.6.14`](https://renovatebot.com/diffs/npm/@storybook%2faddon-essentials/8.6.14/8.6.14)
|
|
[@storybook/addon-interactions](https://redirect.github.com/storybookjs/storybook/tree/next/code/addons/interactions)
([source](https://redirect.github.com/storybookjs/storybook/tree/HEAD/code/addons/interactions))
| devDependencies | pin | [`^8.6.12` ->
`8.6.14`](https://renovatebot.com/diffs/npm/@storybook%2faddon-interactions/8.6.14/8.6.14)
|
|
[@storybook/addon-links](https://redirect.github.com/storybookjs/storybook/tree/next/code/addons/links)
([source](https://redirect.github.com/storybookjs/storybook/tree/HEAD/code/addons/links))
| devDependencies | pin | [`^8.6.12` ->
`8.6.14`](https://renovatebot.com/diffs/npm/@storybook%2faddon-links/8.6.14/8.6.14)
|
|
[@storybook/builder-vite](https://redirect.github.com/storybookjs/storybook/tree/next/code/builders/builder-vite/#readme)
([source](https://redirect.github.com/storybookjs/storybook/tree/HEAD/code/builders/builder-vite))
| devDependencies | pin | [`^8.6.12` ->
`8.6.14`](https://renovatebot.com/diffs/npm/@storybook%2fbuilder-vite/8.6.14/8.6.14)
|
|
[@storybook/vue3](https://redirect.github.com/storybookjs/storybook/tree/next/code/renderers/vue3)
([source](https://redirect.github.com/storybookjs/storybook/tree/HEAD/code/renderers/vue3))
| devDependencies | pin | [`^8.6.12` ->
`8.6.14`](https://renovatebot.com/diffs/npm/@storybook%2fvue3/8.6.14/8.6.14)
|
|
[@storybook/vue3-vite](https://redirect.github.com/storybookjs/storybook/tree/next/code/frameworks/vue3-vite)
([source](https://redirect.github.com/storybookjs/storybook/tree/HEAD/code/frameworks/vue3-vite))
| devDependencies | pin | [`^8.6.12` ->
`8.6.14`](https://renovatebot.com/diffs/npm/@storybook%2fvue3-vite/8.6.14/8.6.14)
|
| [@swc/core](https://swc.rs)
([source](https://redirect.github.com/swc-project/swc)) |
devDependencies | pin | [`^1.10.1` ->
`1.12.4`](https://renovatebot.com/diffs/npm/@swc%2fcore/1.12.4/1.12.4) |
|
[@tailwindcss/typography](https://redirect.github.com/tailwindlabs/tailwindcss-typography)
| devDependencies | pin | [`^0.5.15` ->
`0.5.16`](https://renovatebot.com/diffs/npm/@tailwindcss%2ftypography/0.5.16/0.5.16)
|
|
[@testing-library/vue](https://redirect.github.com/testing-library/vue-testing-library)
| devDependencies | pin | [`^8.0.0` ->
`8.1.0`](https://renovatebot.com/diffs/npm/@testing-library%2fvue/8.1.0/8.1.0)
|
|
[@types/async-exit-hook](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/async-exit-hook)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/async-exit-hook))
| devDependencies | pin | [`^2.0.2` ->
`2.0.2`](https://renovatebot.com/diffs/npm/@types%2fasync-exit-hook/2.0.2/2.0.2)
|
|
[@types/bun](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/bun)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/bun))
| devDependencies | pin | [`^1.2.15` ->
`1.2.16`](https://renovatebot.com/diffs/npm/@types%2fbun/1.2.16/1.2.16)
|
|
[@types/bytes](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/bytes)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/bytes))
| devDependencies | pin | [`^3.1.4` ->
`3.1.5`](https://renovatebot.com/diffs/npm/@types%2fbytes/3.1.5/3.1.5) |
|
[@types/cli-table](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/cli-table)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/cli-table))
| devDependencies | pin | [`^0.3.4` ->
`0.3.4`](https://renovatebot.com/diffs/npm/@types%2fcli-table/0.3.4/0.3.4)
|
|
[@types/command-exists](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/command-exists)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/command-exists))
| devDependencies | pin | [`^1.2.3` ->
`1.2.3`](https://renovatebot.com/diffs/npm/@types%2fcommand-exists/1.2.3/1.2.3)
|
|
[@types/cors](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/cors)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/cors))
| devDependencies | pin | [`^2.8.17` ->
`2.8.19`](https://renovatebot.com/diffs/npm/@types%2fcors/2.8.19/2.8.19)
|
|
[@types/crypto-js](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/crypto-js)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/crypto-js))
| devDependencies | pin | [`^4.2.2` ->
`4.2.2`](https://renovatebot.com/diffs/npm/@types%2fcrypto-js/4.2.2/4.2.2)
|
| @&#8203;types/diff | dependencies | pin | [`^8.0.0` ->
`8.0.0`](https://renovatebot.com/diffs/npm/@types%2fdiff/8.0.0/8.0.0) |
|
[@types/dockerode](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/dockerode)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/dockerode))
| devDependencies | pin | [`^3.3.31` ->
`3.3.41`](https://renovatebot.com/diffs/npm/@types%2fdockerode/3.3.41/3.3.41)
|
|
[@types/eslint-config-prettier](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/eslint-config-prettier)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/eslint-config-prettier))
| devDependencies | pin | [`^6.11.3` ->
`6.11.3`](https://renovatebot.com/diffs/npm/@types%2feslint-config-prettier/6.11.3/6.11.3)
|
|
[@types/fs-extra](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/fs-extra)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/fs-extra))
| devDependencies | pin | [`^11.0.4` ->
`11.0.4`](https://renovatebot.com/diffs/npm/@types%2ffs-extra/11.0.4/11.0.4)
|
|
[@types/graphql-fields](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/graphql-fields)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/graphql-fields))
| devDependencies | pin | [`^1.3.9` ->
`1.3.9`](https://renovatebot.com/diffs/npm/@types%2fgraphql-fields/1.3.9/1.3.9)
|
|
[@types/graphql-type-uuid](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/graphql-type-uuid)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/graphql-type-uuid))
| devDependencies | pin | [`^0.2.6` ->
`0.2.6`](https://renovatebot.com/diffs/npm/@types%2fgraphql-type-uuid/0.2.6/0.2.6)
|
|
[@types/ini](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ini)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/ini))
| devDependencies | pin | [`^4.1.1` ->
`4.1.1`](https://renovatebot.com/diffs/npm/@types%2fini/4.1.1/4.1.1) |
|
[@types/inquirer](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/inquirer)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/inquirer))
| devDependencies | pin | [`^9.0.7` ->
`9.0.8`](https://renovatebot.com/diffs/npm/@types%2finquirer/9.0.8/9.0.8)
|
|
[@types/ip](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ip)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/ip))
| devDependencies | pin | [`^1.1.3` ->
`1.1.3`](https://renovatebot.com/diffs/npm/@types%2fip/1.1.3/1.1.3) |
|
[@types/jsdom](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/jsdom)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jsdom))
| devDependencies | pin | [`^21.1.7` ->
`21.1.7`](https://renovatebot.com/diffs/npm/@types%2fjsdom/21.1.7/21.1.7)
|
|
[@types/lodash](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/lodash)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/lodash))
| devDependencies | pin | [`^4.17.13` ->
`4.17.18`](https://renovatebot.com/diffs/npm/@types%2flodash/4.17.18/4.17.18)
|
|
[@types/lodash-es](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/lodash-es)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/lodash-es))
| devDependencies | pin | [`^4.17.12` ->
`4.17.12`](https://renovatebot.com/diffs/npm/@types%2flodash-es/4.17.12/4.17.12)
|
|
[@types/mustache](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/mustache)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/mustache))
| devDependencies | pin | [`^4.2.5` ->
`4.2.6`](https://renovatebot.com/diffs/npm/@types%2fmustache/4.2.6/4.2.6)
|
|
[@types/node](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node))
| devDependencies | pin | [`^22` ->
`22.15.32`](https://renovatebot.com/diffs/npm/@types%2fnode/22.15.32/22.15.32)
|
|
[@types/node](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node))
| devDependencies | pin | [`^22.0.0` ->
`22.15.32`](https://renovatebot.com/diffs/npm/@types%2fnode/22.15.32/22.15.32)
|
|
[@types/node](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node))
| devDependencies | pin | [`^22.14.0` ->
`22.15.32`](https://renovatebot.com/diffs/npm/@types%2fnode/22.15.32/22.15.32)
|
|
[@types/node](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node))
| devDependencies | pin | [`^22.14.1` ->
`22.15.32`](https://renovatebot.com/diffs/npm/@types%2fnode/22.15.32/22.15.32)
|
|
[@types/node](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node))
| devDependencies | pin | [`^22.13.4` ->
`22.15.32`](https://renovatebot.com/diffs/npm/@types%2fnode/22.15.32/22.15.32)
|
| @&#8203;types/pify | devDependencies | pin | [`^6.0.0` ->
`6.1.0`](https://renovatebot.com/diffs/npm/@types%2fpify/6.1.0/6.1.0) |
|
[@types/semver](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/semver)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/semver))
| devDependencies | pin | [`^7.5.8` ->
`7.7.0`](https://renovatebot.com/diffs/npm/@types%2fsemver/7.7.0/7.7.0)
|
|
[@types/sendmail](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/sendmail)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/sendmail))
| devDependencies | pin | [`^1.4.7` ->
`1.4.7`](https://renovatebot.com/diffs/npm/@types%2fsendmail/1.4.7/1.4.7)
|
|
[@types/stoppable](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/stoppable)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/stoppable))
| devDependencies | pin | [`^1.1.3` ->
`1.1.3`](https://renovatebot.com/diffs/npm/@types%2fstoppable/1.1.3/1.1.3)
|
|
[@types/strftime](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/strftime)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/strftime))
| devDependencies | pin | [`^0.9.8` ->
`0.9.8`](https://renovatebot.com/diffs/npm/@types%2fstrftime/0.9.8/0.9.8)
|
| @&#8203;types/testing-library__vue | devDependencies | pin | [`^5.0.0`
->
`5.3.0`](https://renovatebot.com/diffs/npm/@types%2ftesting-library__vue/5.3.0/5.3.0)
|
|
[@types/uuid](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/uuid)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/uuid))
| devDependencies | pin | [`^10.0.0` ->
`10.0.0`](https://renovatebot.com/diffs/npm/@types%2fuuid/10.0.0/10.0.0)
|
|
[@types/validate-npm-package-name](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/validate-npm-package-name)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/validate-npm-package-name))
| devDependencies | pin | [`^4.0.2` ->
`4.0.2`](https://renovatebot.com/diffs/npm/@types%2fvalidate-npm-package-name/4.0.2/4.0.2)
|
|
[@types/ws](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ws)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/ws))
| devDependencies | pin | [`^8.18.0` ->
`8.18.1`](https://renovatebot.com/diffs/npm/@types%2fws/8.18.1/8.18.1) |
|
[@types/ws](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ws)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/ws))
| devDependencies | pin | [`^8.5.13` ->
`8.18.1`](https://renovatebot.com/diffs/npm/@types%2fws/8.18.1/8.18.1) |
|
[@types/wtfnode](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/wtfnode)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/wtfnode))
| devDependencies | pin | [`^0.7.3` ->
`0.7.3`](https://renovatebot.com/diffs/npm/@types%2fwtfnode/0.7.3/0.7.3)
|
|
[@typescript-eslint/eslint-plugin](https://typescript-eslint.io/packages/eslint-plugin)
([source](https://redirect.github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin))
| devDependencies | pin | [`^8.34.1` ->
`8.34.1`](https://renovatebot.com/diffs/npm/@typescript-eslint%2feslint-plugin/8.34.1/8.34.1)
|
|
[@typescript-eslint/eslint-plugin](https://typescript-eslint.io/packages/eslint-plugin)
([source](https://redirect.github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin))
| devDependencies | pin | [`^8.29.0` ->
`8.34.1`](https://renovatebot.com/diffs/npm/@typescript-eslint%2feslint-plugin/8.34.1/8.34.1)
|
| [@unraid/libvirt](https://redirect.github.com/unraid/libvirt) |
dependencies | pin | [`^2.1.0` ->
`2.1.0`](https://renovatebot.com/diffs/npm/@unraid%2flibvirt/2.1.0/2.1.0)
|
| @&#8203;unraid/shared-callbacks | dependencies | pin | [`^1.1.1` ->
`1.1.1`](https://renovatebot.com/diffs/npm/@unraid%2fshared-callbacks/1.1.1/1.1.1)
|
| @&#8203;unraid/tailwind-rem-to-rem | devDependencies | pin | [`^1.1.0`
->
`1.1.0`](https://renovatebot.com/diffs/npm/@unraid%2ftailwind-rem-to-rem/1.1.0/1.1.0)
|
|
[@vitejs/plugin-vue](https://redirect.github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue#readme)
([source](https://redirect.github.com/vitejs/vite-plugin-vue/tree/HEAD/packages/plugin-vue))
| devDependencies | pin | [`^5.0.0` ->
`5.2.4`](https://renovatebot.com/diffs/npm/@vitejs%2fplugin-vue/5.2.4/5.2.4)
|
|
[@vitejs/plugin-vue-jsx](https://redirect.github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue-jsx#readme)
([source](https://redirect.github.com/vitejs/vite-plugin-vue/tree/HEAD/packages/plugin-vue-jsx))
| devDependencies | pin | [`^4.1.1` ->
`4.2.0`](https://renovatebot.com/diffs/npm/@vitejs%2fplugin-vue-jsx/4.2.0/4.2.0)
|
|
[@vitest/coverage-v8](https://redirect.github.com/vitest-dev/vitest/tree/main/packages/coverage-v8#readme)
([source](https://redirect.github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8))
| devDependencies | pin | [`^3.1.1` ->
`3.2.4`](https://renovatebot.com/diffs/npm/@vitest%2fcoverage-v8/3.2.4/3.2.4)
|
|
[@vitest/coverage-v8](https://redirect.github.com/vitest-dev/vitest/tree/main/packages/coverage-v8#readme)
([source](https://redirect.github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8))
| devDependencies | pin | [`^3.0.0` ->
`3.2.4`](https://renovatebot.com/diffs/npm/@vitest%2fcoverage-v8/3.2.4/3.2.4)
|
|
[@vitest/coverage-v8](https://redirect.github.com/vitest-dev/vitest/tree/main/packages/coverage-v8#readme)
([source](https://redirect.github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8))
| devDependencies | pin | [`^3.0.5` ->
`3.2.4`](https://renovatebot.com/diffs/npm/@vitest%2fcoverage-v8/3.2.4/3.2.4)
|
|
[@vitest/ui](https://redirect.github.com/vitest-dev/vitest/tree/main/packages/ui#readme)
([source](https://redirect.github.com/vitest-dev/vitest/tree/HEAD/packages/ui))
| devDependencies | pin | [`^3.0.0` ->
`3.2.4`](https://renovatebot.com/diffs/npm/@vitest%2fui/3.2.4/3.2.4) |
|
[@vitest/ui](https://redirect.github.com/vitest-dev/vitest/tree/main/packages/ui#readme)
([source](https://redirect.github.com/vitest-dev/vitest/tree/HEAD/packages/ui))
| devDependencies | pin | [`^3.0.5` ->
`3.2.4`](https://renovatebot.com/diffs/npm/@vitest%2fui/3.2.4/3.2.4) |
| [@vue/apollo-composable](https://apollo.vuejs.org/)
([source](https://redirect.github.com/vuejs/vue-apollo/tree/HEAD/packages/vue-apollo-composable))
| dependencies | pin | [`^4.2.1` ->
`4.2.2`](https://renovatebot.com/diffs/npm/@vue%2fapollo-composable/4.2.2/4.2.2)
|
| [@vue/apollo-util](https://apollo.vuejs.org/)
([source](https://redirect.github.com/vuejs/vue-apollo/tree/HEAD/packages/vue-apollo-util))
| devDependencies | pin | [`^4.0.0-beta.6` ->
`4.2.2`](https://renovatebot.com/diffs/npm/@vue%2fapollo-util/4.2.2/4.2.2)
|
| [@vue/test-utils](https://redirect.github.com/vuejs/test-utils) |
devDependencies | pin | [`^2.4.6` ->
`2.4.6`](https://renovatebot.com/diffs/npm/@vue%2ftest-utils/2.4.6/2.4.6)
|
| [@vue/test-utils](https://redirect.github.com/vuejs/test-utils) |
devDependencies | pin | [`^2.4.0` ->
`2.4.6`](https://renovatebot.com/diffs/npm/@vue%2ftest-utils/2.4.6/2.4.6)
|
| [@vue/tsconfig](https://redirect.github.com/vuejs/tsconfig) |
devDependencies | pin | [`^0.7.0` ->
`0.7.0`](https://renovatebot.com/diffs/npm/@vue%2ftsconfig/0.7.0/0.7.0)
|
|
[@vueuse/components](https://redirect.github.com/vueuse/vueuse/tree/main/packages/components#readme)
([source](https://redirect.github.com/vueuse/vueuse/tree/HEAD/packages/components))
| dependencies | pin | [`^13.0.0` ->
`13.4.0`](https://renovatebot.com/diffs/npm/@vueuse%2fcomponents/13.4.0/13.4.0)
|
| [@vueuse/core](https://redirect.github.com/vueuse/vueuse)
([source](https://redirect.github.com/vueuse/vueuse/tree/HEAD/packages/core))
| devDependencies | pin | [`^13.0.0` ->
`13.4.0`](https://renovatebot.com/diffs/npm/@vueuse%2fcore/13.4.0/13.4.0)
|
| [@vueuse/core](https://redirect.github.com/vueuse/vueuse)
([source](https://redirect.github.com/vueuse/vueuse/tree/HEAD/packages/core))
| dependencies | pin | [`^13.0.0` ->
`13.4.0`](https://renovatebot.com/diffs/npm/@vueuse%2fcore/13.4.0/13.4.0)
|
|
[@vueuse/integrations](https://redirect.github.com/vueuse/vueuse/tree/main/packages/integrations#readme)
([source](https://redirect.github.com/vueuse/vueuse/tree/HEAD/packages/integrations))
| dependencies | pin | [`^13.0.0` ->
`13.4.0`](https://renovatebot.com/diffs/npm/@vueuse%2fintegrations/13.4.0/13.4.0)
|
|
[@vueuse/nuxt](https://redirect.github.com/vueuse/vueuse/tree/main/packages/nuxt#readme)
([source](https://redirect.github.com/vueuse/vueuse/tree/HEAD/packages/nuxt))
| devDependencies | pin | [`^13.0.0` ->
`13.4.0`](https://renovatebot.com/diffs/npm/@vueuse%2fnuxt/13.4.0/13.4.0)
|
| [accesscontrol](https://redirect.github.com/onury/accesscontrol) |
dependencies | pin | [`^2.2.1` ->
`2.2.1`](https://renovatebot.com/diffs/npm/accesscontrol/2.2.1/2.2.1) |
| [autoprefixer](https://redirect.github.com/postcss/autoprefixer) |
devDependencies | pin | [`^10.4.20` ->
`10.4.21`](https://renovatebot.com/diffs/npm/autoprefixer/10.4.21/10.4.21)
|
| [bycontract](https://redirect.github.com/dsheiko/bycontract) |
dependencies | pin | [`^2.0.11` ->
`2.0.11`](https://renovatebot.com/diffs/npm/bycontract/2.0.11/2.0.11) |
| [bytes](https://redirect.github.com/visionmedia/bytes.js) |
dependencies | pin | [`^3.1.2` ->
`3.1.2`](https://renovatebot.com/diffs/npm/bytes/3.1.2/3.1.2) |
| [cache-manager](https://redirect.github.com/jaredwray/cacheable)
([source](https://redirect.github.com/jaredwray/cacheable/tree/HEAD/packages/cache-manager))
| dependencies | pin | [`^7.0.0` ->
`7.0.0`](https://renovatebot.com/diffs/npm/cache-manager/7.0.0/7.0.0) |
|
[cacheable-lookup](https://redirect.github.com/szmarczak/cacheable-lookup)
| dependencies | pin | [`^7.0.0` ->
`7.0.0`](https://renovatebot.com/diffs/npm/cacheable-lookup/7.0.0/7.0.0)
|
|
[camelcase-keys](https://redirect.github.com/sindresorhus/camelcase-keys)
| peerDependencies | pin | [`^9.1.3` ->
`9.1.3`](https://renovatebot.com/diffs/npm/camelcase-keys/9.1.3/9.1.3) |
|
[camelcase-keys](https://redirect.github.com/sindresorhus/camelcase-keys)
| devDependencies | pin | [`^9.1.3` ->
`9.1.3`](https://renovatebot.com/diffs/npm/camelcase-keys/9.1.3/9.1.3) |
|
[camelcase-keys](https://redirect.github.com/sindresorhus/camelcase-keys)
| dependencies | pin | [`^9.1.3` ->
`9.1.3`](https://renovatebot.com/diffs/npm/camelcase-keys/9.1.3/9.1.3) |
| [casbin](http://casbin.org)
([source](https://redirect.github.com/casbin/node-casbin)) |
dependencies | pin | [`^5.32.0` ->
`5.38.0`](https://renovatebot.com/diffs/npm/casbin/5.38.0/5.38.0) |
| [chalk](https://redirect.github.com/chalk/chalk) | dependencies | pin
| [`^5.4.1` ->
`5.4.1`](https://renovatebot.com/diffs/npm/chalk/5.4.1/5.4.1) |
| [chalk](https://redirect.github.com/chalk/chalk) | dependencies | pin
| [`^5.0.0` ->
`5.4.1`](https://renovatebot.com/diffs/npm/chalk/5.4.1/5.4.1) |
|
[change-case](https://redirect.github.com/blakeembrey/change-case/tree/master/packages/change-case#readme)
([source](https://redirect.github.com/blakeembrey/change-case)) |
dependencies | pin | [`^5.4.4` ->
`5.4.4`](https://renovatebot.com/diffs/npm/change-case/5.4.4/5.4.4) |
| [chokidar](https://redirect.github.com/paulmillr/chokidar) |
dependencies | pin | [`^4.0.1` ->
`4.0.3`](https://renovatebot.com/diffs/npm/chokidar/4.0.3/4.0.3) |
|
[class-transformer](https://redirect.github.com/typestack/class-transformer)
| devDependencies | pin | [`^0.5.1` ->
`0.5.1`](https://renovatebot.com/diffs/npm/class-transformer/0.5.1/0.5.1)
|
|
[class-transformer](https://redirect.github.com/typestack/class-transformer)
| peerDependencies | pin | [`^0.5.1` ->
`0.5.1`](https://renovatebot.com/diffs/npm/class-transformer/0.5.1/0.5.1)
|
|
[class-transformer](https://redirect.github.com/typestack/class-transformer)
| dependencies | pin | [`^0.5.1` ->
`0.5.1`](https://renovatebot.com/diffs/npm/class-transformer/0.5.1/0.5.1)
|
|
[class-validator](https://redirect.github.com/typestack/class-validator)
| peerDependencies | pin | [`^0.14.1` ->
`0.14.2`](https://renovatebot.com/diffs/npm/class-validator/0.14.2/0.14.2)
|
|
[class-validator](https://redirect.github.com/typestack/class-validator)
| devDependencies | pin | [`^0.14.1` ->
`0.14.2`](https://renovatebot.com/diffs/npm/class-validator/0.14.2/0.14.2)
|
|
[class-validator](https://redirect.github.com/typestack/class-validator)
| dependencies | pin | [`^0.14.1` ->
`0.14.2`](https://renovatebot.com/diffs/npm/class-validator/0.14.2/0.14.2)
|
| [class-variance-authority](https://redirect.github.com/joe-bell/cva) |
dependencies | pin | [`^0.7.1` ->
`0.7.1`](https://renovatebot.com/diffs/npm/class-variance-authority/0.7.1/0.7.1)
|
| [cli-table](https://redirect.github.com/Automattic/cli-table) |
dependencies | pin | [`^0.3.11` ->
`0.3.11`](https://renovatebot.com/diffs/npm/cli-table/0.3.11/0.3.11) |
| [clsx](https://redirect.github.com/lukeed/clsx) | dependencies | pin |
[`^2.1.1` ->
`2.1.1`](https://renovatebot.com/diffs/npm/clsx/2.1.1/2.1.1) |
|
[command-exists](https://redirect.github.com/mathisonian/command-exists)
| dependencies | pin | [`^1.2.9` ->
`1.2.9`](https://renovatebot.com/diffs/npm/command-exists/1.2.9/1.2.9) |
| [commander](https://redirect.github.com/tj/commander.js) |
dependencies | pin | [`^14.0.0` ->
`14.0.0`](https://renovatebot.com/diffs/npm/commander/13.1.0/14.0.0) |
| [commander](https://redirect.github.com/tj/commander.js) |
dependencies | pin | [`^14.0.0` ->
`14.0.0`](https://renovatebot.com/diffs/npm/commander/14.0.0/14.0.0) |
|
[concurrently](https://redirect.github.com/open-cli-tools/concurrently)
| devDependencies | pin | [`^9.1.2` ->
`9.1.2`](https://renovatebot.com/diffs/npm/concurrently/9.1.2/9.1.2) |
|
[conventional-changelog](https://redirect.github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog#readme)
([source](https://redirect.github.com/conventional-changelog/conventional-changelog/tree/HEAD/packages/conventional-changelog))
| dependencies | pin | [`^6.0.0` ->
`6.0.0`](https://renovatebot.com/diffs/npm/conventional-changelog/6.0.0/6.0.0)
|
| [convert](https://convert.js.org/)
([source](https://redirect.github.com/jonahsnider/convert)) |
dependencies | pin | [`^5.8.0` ->
`5.12.0`](https://renovatebot.com/diffs/npm/convert/5.12.0/5.12.0) |
| [cookie](https://redirect.github.com/jshttp/cookie) | dependencies |
pin | [`^1.0.2` ->
`1.0.2`](https://renovatebot.com/diffs/npm/cookie/1.0.2/1.0.2) |
|
[create-create-app](https://redirect.github.com/uetchy/create-create-app)
| dependencies | pin | [`^7.3.0` ->
`7.3.0`](https://renovatebot.com/diffs/npm/create-create-app/7.3.0/7.3.0)
|
| [cross-fetch](https://redirect.github.com/lquixada/cross-fetch) |
dependencies | pin | [`^4.0.0` ->
`4.1.0`](https://renovatebot.com/diffs/npm/cross-fetch/4.1.0/4.1.0) |
| [crypto-js](https://redirect.github.com/brix/crypto-js) | dependencies
| pin | [`^4.2.0` ->
`4.2.0`](https://renovatebot.com/diffs/npm/crypto-js/4.2.0/4.2.0) |
| [date-fns](https://redirect.github.com/date-fns/date-fns) |
dependencies | pin | [`^4.1.0` ->
`4.1.0`](https://renovatebot.com/diffs/npm/date-fns/4.1.0/4.1.0) |
| [dayjs](https://day.js.org)
([source](https://redirect.github.com/iamkun/dayjs)) | dependencies |
pin | [`^1.11.13` ->
`1.11.13`](https://renovatebot.com/diffs/npm/dayjs/1.11.13/1.11.13) |
| [diff](https://redirect.github.com/kpdecker/jsdiff) | dependencies |
pin | [`^8.0.0` ->
`8.0.2`](https://renovatebot.com/diffs/npm/diff/8.0.2/8.0.2) |
| [dockerode](https://redirect.github.com/apocas/dockerode) |
dependencies | pin | [`^4.0.5` ->
`4.0.7`](https://renovatebot.com/diffs/npm/dockerode/4.0.7/4.0.7) |
| [dompurify](https://redirect.github.com/cure53/DOMPurify) |
dependencies | pin | [`^3.2.5` ->
`3.2.6`](https://renovatebot.com/diffs/npm/dompurify/3.2.6/3.2.6) |
| [dotenv](https://redirect.github.com/motdotla/dotenv) | dependencies |
pin | [`^16.4.5` ->
`16.5.0`](https://renovatebot.com/diffs/npm/dotenv/16.5.0/16.5.0) |
| [eslint](https://eslint.org)
([source](https://redirect.github.com/eslint/eslint)) | devDependencies
| pin | [`^9.21.0` ->
`9.29.0`](https://renovatebot.com/diffs/npm/eslint/9.29.0/9.29.0) |
| [eslint](https://eslint.org)
([source](https://redirect.github.com/eslint/eslint)) | devDependencies
| pin | [`^9.17.0` ->
`9.29.0`](https://renovatebot.com/diffs/npm/eslint/9.29.0/9.29.0) |
| [eslint](https://eslint.org)
([source](https://redirect.github.com/eslint/eslint)) | devDependencies
| pin | [`^9.20.1` ->
`9.29.0`](https://renovatebot.com/diffs/npm/eslint/9.29.0/9.29.0) |
|
[eslint-config-prettier](https://redirect.github.com/prettier/eslint-config-prettier)
| devDependencies | pin | [`^10.0.0` ->
`10.1.5`](https://renovatebot.com/diffs/npm/eslint-config-prettier/10.1.5/10.1.5)
|
|
[eslint-import-resolver-typescript](https://redirect.github.com/import-js/eslint-import-resolver-typescript)
| devDependencies | pin | [`^4.4.4` ->
`4.4.4`](https://renovatebot.com/diffs/npm/eslint-import-resolver-typescript/4.4.4/4.4.4)
|
|
[eslint-plugin-import](https://redirect.github.com/import-js/eslint-plugin-import)
| devDependencies | pin | [`^2.31.0` ->
`2.31.0`](https://renovatebot.com/diffs/npm/eslint-plugin-import/2.31.0/2.31.0)
|
|
[eslint-plugin-n](https://redirect.github.com/eslint-community/eslint-plugin-n)
| devDependencies | pin | [`^17.0.0` ->
`17.20.0`](https://renovatebot.com/diffs/npm/eslint-plugin-n/17.20.0/17.20.0)
|
|
[eslint-plugin-no-relative-import-paths](https://redirect.github.com/MelvinVermeer/eslint-plugin-no-relative-import-paths)
| devDependencies | pin | [`^1.6.1` ->
`1.6.1`](https://renovatebot.com/diffs/npm/eslint-plugin-no-relative-import-paths/1.6.1/1.6.1)
|
|
[eslint-plugin-prettier](https://redirect.github.com/prettier/eslint-plugin-prettier)
| devDependencies | pin | [`^5.2.3` ->
`5.5.0`](https://renovatebot.com/diffs/npm/eslint-plugin-prettier/5.5.0/5.5.0)
|
| [eslint-plugin-vue](https://eslint.vuejs.org)
([source](https://redirect.github.com/vuejs/eslint-plugin-vue)) |
devDependencies | pin | [`^10.0.0` ->
`10.2.0`](https://renovatebot.com/diffs/npm/eslint-plugin-vue/10.2.0/10.2.0)
|
| [execa](https://redirect.github.com/sindresorhus/execa) |
peerDependencies | pin | [`^9.5.1` ->
`9.6.0`](https://renovatebot.com/diffs/npm/execa/9.6.0/9.6.0) |
| [execa](https://redirect.github.com/sindresorhus/execa) |
devDependencies | pin | [`^9.5.1` ->
`9.6.0`](https://renovatebot.com/diffs/npm/execa/9.6.0/9.6.0) |
| [execa](https://redirect.github.com/sindresorhus/execa) | dependencies
| pin | [`^9.5.1` ->
`9.6.0`](https://renovatebot.com/diffs/npm/execa/9.6.0/9.6.0) |
| [exit-hook](https://redirect.github.com/sindresorhus/exit-hook) |
dependencies | pin | [`^4.0.0` ->
`4.0.0`](https://renovatebot.com/diffs/npm/exit-hook/4.0.0/4.0.0) |
| [fast-check](https://fast-check.dev/)
([source](https://redirect.github.com/dubzzz/fast-check/tree/HEAD/packages/fast-check))
| devDependencies | pin | [`^4.1.1` ->
`4.1.1`](https://renovatebot.com/diffs/npm/fast-check/4.1.1/4.1.1) |
| [fastify](https://fastify.dev/)
([source](https://redirect.github.com/fastify/fastify)) | dependencies |
pin | [`^5.2.1` ->
`5.4.0`](https://renovatebot.com/diffs/npm/fastify/5.4.0/5.4.0) |
| [filenamify](https://redirect.github.com/sindresorhus/filenamify) |
dependencies | pin | [`^6.0.0` ->
`6.0.0`](https://renovatebot.com/diffs/npm/filenamify/6.0.0/6.0.0) |
| [focus-trap](https://redirect.github.com/focus-trap/focus-trap) |
dependencies | pin | [`^7.6.2` ->
`7.6.5`](https://renovatebot.com/diffs/npm/focus-trap/7.6.5/7.6.5) |
| [fs-extra](https://redirect.github.com/jprichardson/node-fs-extra) |
dependencies | pin | [`^11.3.0` ->
`11.3.0`](https://renovatebot.com/diffs/npm/fs-extra/11.3.0/11.3.0) |
| [fs-extra](https://redirect.github.com/jprichardson/node-fs-extra) |
dependencies | pin | [`^11.2.0` ->
`11.3.0`](https://renovatebot.com/diffs/npm/fs-extra/11.3.0/11.3.0) |
| [glob](https://redirect.github.com/isaacs/node-glob) | dependencies |
pin | [`^11.0.1` ->
`11.0.1`](https://renovatebot.com/diffs/npm/glob/11.0.1/11.0.1) |
| [glob](https://redirect.github.com/isaacs/node-glob) | dependencies |
pin | [`^11.0.1` ->
`11.0.3`](https://renovatebot.com/diffs/npm/glob/11.0.3/11.0.3) |
| [global-agent](https://redirect.github.com/gajus/global-agent) |
dependencies | pin | [`^3.0.0` ->
`3.0.0`](https://renovatebot.com/diffs/npm/global-agent/3.0.0/3.0.0) |
| [got](https://redirect.github.com/sindresorhus/got) | peerDependencies
| pin | [`^14.4.6` ->
`14.4.7`](https://renovatebot.com/diffs/npm/got/14.4.7/14.4.7) |
| [got](https://redirect.github.com/sindresorhus/got) | devDependencies
| pin | [`^14.4.6` ->
`14.4.7`](https://renovatebot.com/diffs/npm/got/14.4.7/14.4.7) |
| [got](https://redirect.github.com/sindresorhus/got) | dependencies |
pin | [`^14.4.6` ->
`14.4.7`](https://renovatebot.com/diffs/npm/got/14.4.7/14.4.7) |
| [graphql](https://redirect.github.com/graphql/graphql-js) |
dependencies | pin | [`^16.11.0` ->
`16.11.0`](https://renovatebot.com/diffs/npm/graphql/16.11.0/16.11.0) |
| [graphql](https://redirect.github.com/graphql/graphql-js) |
peerDependencies | pin | [`^16.9.0` ->
`16.11.0`](https://renovatebot.com/diffs/npm/graphql/16.11.0/16.11.0) |
| [graphql](https://redirect.github.com/graphql/graphql-js) |
devDependencies | pin | [`^16.9.0` ->
`16.11.0`](https://renovatebot.com/diffs/npm/graphql/16.11.0/16.11.0) |
| [graphql](https://redirect.github.com/graphql/graphql-js) |
dependencies | pin | [`^16.9.0` ->
`16.11.0`](https://renovatebot.com/diffs/npm/graphql/16.11.0/16.11.0) |
| graphql-codegen-typescript-validation-schema | devDependencies | pin |
[`^0.17.0` ->
`0.17.1`](https://renovatebot.com/diffs/npm/graphql-codegen-typescript-validation-schema/0.17.1/0.17.1)
|
|
[graphql-fields](https://redirect.github.com/robrichard/graphql-fields)
| dependencies | pin | [`^2.0.3` ->
`2.0.3`](https://renovatebot.com/diffs/npm/graphql-fields/2.0.3/2.0.3) |
| [graphql-scalars](https://redirect.github.com/Urigo/graphql-scalars) |
peerDependencies | pin | [`^1.23.0` ->
`1.24.2`](https://renovatebot.com/diffs/npm/graphql-scalars/1.24.2/1.24.2)
|
| [graphql-scalars](https://redirect.github.com/Urigo/graphql-scalars) |
devDependencies | pin | [`^1.23.0` ->
`1.24.2`](https://renovatebot.com/diffs/npm/graphql-scalars/1.24.2/1.24.2)
|
| [graphql-scalars](https://redirect.github.com/Urigo/graphql-scalars) |
dependencies | pin | [`^1.23.0` ->
`1.24.2`](https://renovatebot.com/diffs/npm/graphql-scalars/1.24.2/1.24.2)
|
| [graphql-ws](https://the-guild.dev/graphql/ws)
([source](https://redirect.github.com/enisdenjo/graphql-ws)) |
dependencies | pin | [`^6.0.0` ->
`6.0.5`](https://renovatebot.com/diffs/npm/graphql-ws/6.0.5/6.0.5) |
| [graphql-ws](https://the-guild.dev/graphql/ws)
([source](https://redirect.github.com/enisdenjo/graphql-ws)) |
peerDependencies | pin | [`^6.0.0` ->
`6.0.5`](https://renovatebot.com/diffs/npm/graphql-ws/6.0.5/6.0.5) |
| [graphql-ws](https://the-guild.dev/graphql/ws)
([source](https://redirect.github.com/enisdenjo/graphql-ws)) |
devDependencies | pin | [`^6.0.0` ->
`6.0.5`](https://renovatebot.com/diffs/npm/graphql-ws/6.0.5/6.0.5) |
| [happy-dom](https://redirect.github.com/capricorn86/happy-dom) |
devDependencies | pin | [`^18.0.0` ->
`18.0.0`](https://renovatebot.com/diffs/npm/happy-dom/18.0.0/18.0.0) |
| [hex-to-rgba](https://redirect.github.com/misund/hex-to-rgba) |
dependencies | pin | [`^2.0.1` ->
`2.0.1`](https://renovatebot.com/diffs/npm/hex-to-rgba/2.0.1/2.0.1) |
| [highlight.js](https://highlightjs.org/)
([source](https://redirect.github.com/highlightjs/highlight.js)) |
dependencies | pin | [`^11.11.1` ->
`11.11.1`](https://renovatebot.com/diffs/npm/highlight.js/11.11.1/11.11.1)
|
|
[html-sloppy-escaper](https://redirect.github.com/WebReflection/html-sloppy-escaper)
| dependencies | pin | [`^0.1.0` ->
`0.1.0`](https://renovatebot.com/diffs/npm/html-sloppy-escaper/0.1.0/0.1.0)
|
| [http-server](https://redirect.github.com/http-party/http-server) |
devDependencies | pin | [`^14.1.1` ->
`14.1.1`](https://renovatebot.com/diffs/npm/http-server/14.1.1/14.1.1) |
| [ignore](https://redirect.github.com/kaelzhang/node-ignore) |
dependencies | pin | [`^7.0.0` ->
`7.0.5`](https://renovatebot.com/diffs/npm/ignore/7.0.5/7.0.5) |
| [ini](https://redirect.github.com/npm/ini) | peerDependencies | pin |
[`^5.0.0` -> `5.0.0`](https://renovatebot.com/diffs/npm/ini/5.0.0/5.0.0)
|
| [ini](https://redirect.github.com/npm/ini) | devDependencies | pin |
[`^5.0.0` -> `5.0.0`](https://renovatebot.com/diffs/npm/ini/5.0.0/5.0.0)
|
| [ini](https://redirect.github.com/npm/ini) | dependencies | pin |
[`^5.0.0` -> `5.0.0`](https://renovatebot.com/diffs/npm/ini/5.0.0/5.0.0)
|
|
[inquirer](https://redirect.github.com/SBoudrias/Inquirer.js/blob/main/packages/inquirer/README.md)
([source](https://redirect.github.com/SBoudrias/Inquirer.js)) |
dependencies | pin | [`^12.5.2` ->
`12.6.3`](https://renovatebot.com/diffs/npm/inquirer/12.6.3/12.6.3) |
| [ip](https://redirect.github.com/indutny/node-ip) | dependencies | pin
| [`^2.0.1` ->
`2.0.1`](https://renovatebot.com/diffs/npm/ip/2.0.1/2.0.1) |
|
[isomorphic-dompurify](https://redirect.github.com/kkomelin/isomorphic-dompurify)
| dependencies | pin | [`^2.19.0` ->
`2.25.0`](https://renovatebot.com/diffs/npm/isomorphic-dompurify/2.25.0/2.25.0)
|
| [jiti](https://redirect.github.com/unjs/jiti) | overrides | pin | [`2`
-> `2.4.2`](https://renovatebot.com/diffs/npm/jiti/2.4.2/2.4.2) |
| [jiti](https://redirect.github.com/unjs/jiti) | devDependencies | pin
| [`^2.4.0` ->
`2.4.2`](https://renovatebot.com/diffs/npm/jiti/2.4.2/2.4.2) |
| [jose](https://redirect.github.com/panva/jose) | peerDependencies |
pin | [`^6.0.0` ->
`6.0.11`](https://renovatebot.com/diffs/npm/jose/6.0.11/6.0.11) |
| [jose](https://redirect.github.com/panva/jose) | devDependencies | pin
| [`^6.0.0` ->
`6.0.11`](https://renovatebot.com/diffs/npm/jose/6.0.11/6.0.11) |
| [jose](https://redirect.github.com/panva/jose) | dependencies | pin |
[`^6.0.0` ->
`6.0.11`](https://renovatebot.com/diffs/npm/jose/6.0.11/6.0.11) |
|
[json-bigint-patch](https://redirect.github.com/ardatan/json-bigint-patch)
| dependencies | pin | [`^0.0.8` ->
`0.0.8`](https://renovatebot.com/diffs/npm/json-bigint-patch/0.0.8/0.0.8)
|
| [kebab-case](https://redirect.github.com/joakimbeng/kebab-case) |
dependencies | pin | [`^2.0.1` ->
`2.0.2`](https://renovatebot.com/diffs/npm/kebab-case/2.0.2/2.0.2) |
| [lint-staged](https://redirect.github.com/lint-staged/lint-staged) |
devDependencies | pin | [`^16.0.0` ->
`16.1.2`](https://renovatebot.com/diffs/npm/lint-staged/16.1.2/16.1.2) |
| [lodash-es](https://lodash.com/custom-builds)
([source](https://redirect.github.com/lodash/lodash)) | devDependencies
| pin | [`^4.17.21` ->
`4.17.21`](https://renovatebot.com/diffs/npm/lodash-es/4.17.21/4.17.21)
|
| [lodash-es](https://lodash.com/custom-builds)
([source](https://redirect.github.com/lodash/lodash)) | peerDependencies
| pin | [`^4.17.21` ->
`4.17.21`](https://renovatebot.com/diffs/npm/lodash-es/4.17.21/4.17.21)
|
| [lodash-es](https://lodash.com/custom-builds)
([source](https://redirect.github.com/lodash/lodash)) | dependencies |
pin | [`^4.17.21` ->
`4.17.21`](https://renovatebot.com/diffs/npm/lodash-es/4.17.21/4.17.21)
|
| [lucide-vue-next](https://lucide.dev)
([source](https://redirect.github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-vue-next))
| dependencies | pin | [`^0.519.0` ->
`0.519.0`](https://renovatebot.com/diffs/npm/lucide-vue-next/0.519.0/0.519.0)
|
| [marked](https://marked.js.org)
([source](https://redirect.github.com/markedjs/marked)) | dependencies |
pin | [`^15.0.0` ->
`15.0.12`](https://renovatebot.com/diffs/npm/marked/15.0.12/15.0.12) |
|
[marked-base-url](https://redirect.github.com/markedjs/marked-base-url)
| dependencies | pin | [`^1.1.6` ->
`1.1.6`](https://renovatebot.com/diffs/npm/marked-base-url/1.1.6/1.1.6)
|
| [multi-ini](https://redirect.github.com/evangelion1204/multi-ini) |
dependencies | pin | [`^2.3.2` ->
`2.3.2`](https://renovatebot.com/diffs/npm/multi-ini/2.3.2/2.3.2) |
| [mustache](https://redirect.github.com/janl/mustache.js) |
dependencies | pin | [`^4.2.0` ->
`4.2.0`](https://renovatebot.com/diffs/npm/mustache/4.2.0/4.2.0) |
| [nest-authz](https://redirect.github.com/node-casbin/nest-authz) |
peerDependencies | pin | [`^2.14.0` ->
`2.17.0`](https://renovatebot.com/diffs/npm/nest-authz/2.17.0/2.17.0) |
| [nest-authz](https://redirect.github.com/node-casbin/nest-authz) |
devDependencies | pin | [`^2.14.0` ->
`2.17.0`](https://renovatebot.com/diffs/npm/nest-authz/2.17.0/2.17.0) |
| [nest-authz](https://redirect.github.com/node-casbin/nest-authz) |
dependencies | pin | [`^2.14.0` ->
`2.17.0`](https://renovatebot.com/diffs/npm/nest-authz/2.17.0/2.17.0) |
| [nest-commander](https://nest-commander.jaymcdoniel.dev)
([source](https://redirect.github.com/jmcdo29/nest-commander/tree/HEAD/pacakges/nest-commander))
| dependencies | pin | [`^3.15.0` ->
`3.17.0`](https://renovatebot.com/diffs/npm/nest-commander/3.17.0/3.17.0)
|
| [nestjs-pino](https://redirect.github.com/iamolegga/nestjs-pino) |
dependencies | pin | [`^4.1.0` ->
`4.4.0`](https://renovatebot.com/diffs/npm/nestjs-pino/4.4.0/4.4.0) |
| [node](https://redirect.github.com/actions/node-versions) | uses-with
| pin | `22.x` -> `22.17.0` |
| [node-cache](https://redirect.github.com/node-cache/node-cache) |
dependencies | pin | [`^5.1.2` ->
`5.1.2`](https://renovatebot.com/diffs/npm/node-cache/5.1.2/5.1.2) |
|
[node-window-polyfill](https://redirect.github.com/tgorka/node-window-polyfill)
| dependencies | pin | [`^1.0.2` ->
`1.0.4`](https://renovatebot.com/diffs/npm/node-window-polyfill/1.0.4/1.0.4)
|
| [nodemon](https://nodemon.io)
([source](https://redirect.github.com/remy/nodemon)) | devDependencie

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Pujit Mehrotra <pujit@lime-technology.com>
2025-07-08 10:30:15 -04:00
Eli Bosley
345e83bfb0 feat: upgrade nuxt-custom-elements (#1461)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added new modal dialogs and UI components, including activation steps,
OS update feedback, and expanded notification management.
* Introduced a plugin to configure internationalization, state
management, and Apollo client support in web components.
* Added a new Log Viewer page with a streamlined interface for viewing
logs.

* **Improvements**
* Centralized Pinia state management by consolidating all stores to use
a shared global Pinia instance.
* Simplified component templates by removing redundant
internationalization host wrappers.
* Enhanced ESLint configuration with stricter rules and global variable
declarations.
* Refined custom element build process to prevent jQuery conflicts and
optimize minification.
* Updated component imports and templates for consistent structure and
maintainability.
* Streamlined log viewer dropdowns using simplified select components
with improved formatting.
* Improved notification sidebar with filtering by importance and modular
components.
* Replaced legacy notification popups with new UI components and added
automatic root session creation for localhost requests.
* Updated OS version display and user profile UI with refined styling
and component usage.

* **Bug Fixes**
* Fixed component tag capitalization and improved type annotations
across components.

* **Chores**
* Updated development dependencies including ESLint plugins and build
tools.
* Removed deprecated log viewer patch class and cleaned up related test
fixtures.
  * Removed unused imports and simplified Apollo client setup.
* Cleaned up test mocks and removed obsolete i18n host component tests.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210730229632804

---------

Co-authored-by: Pujit Mehrotra <pujit@lime-technology.com>
Co-authored-by: Zack Spear <zackspear@users.noreply.github.com>
2025-07-08 10:05:39 -04:00
Pujit Mehrotra
7be8bc84d3 fix(connect): mothership connection (#1464)
---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210709463978079

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Improved management of cloud connection status and error handling for
DNS resolution issues.
* Introduced a centralized controller for managing mothership connection
lifecycle and subscriptions.

* **Refactor**
* Streamlined event handling and resource management for mothership
connections.
* Consolidated connection logic to enhance reliability and
maintainability.
* Optimized initialization process by deferring GraphQL client creation
until needed.

* **Chores**
* Updated module configuration to include the new controller for better
dependency management.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-07 17:14:47 -04:00
Eli Bosley
4d97e1465b chore: update lockfile after reverting package.json dependencies 2025-07-05 12:52:23 -04:00
Eli Bosley
94420e4d45 revert: revert package.json dependency updates from commit 711cc9a for api and packages/* 2025-07-05 12:49:25 -04:00
Michael Datelle
711cc9ac92 feat: build out docker components (#1427)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Introduced comprehensive, customizable Accordion, Dialog,
DropdownMenu, and Select UI components with enhanced prop-driven and
slot-based APIs.
* Added grouped exports for UI primitives, simplifying imports and
usage.
* Added new Storybook stories demonstrating varied usage scenarios for
Accordion, Dialog, DropdownMenu, and Select components.

* **Refactor**
* Replaced external UI dependencies with locally defined, typed
components for Accordion, Dialog, DropdownMenu, and Select.
* Streamlined component APIs by consolidating exports to main components
and type exports, removing subcomponent exports.
* Simplified dialog and dropdown menu implementations with explicit
props, events, and slots.
* Updated component styles and class bindings for improved appearance
and interaction.
* Refined select component into a fully featured, typed implementation
supporting grouping and multiple selection.
* Replaced custom dropdown menu implementation in user profile with the
new DropdownMenu component.
* Simplified internal prop forwarding using reactive utilities for
dropdown menu and select subcomponents.
* Improved dropdown menu stories with declarative props and slots,
removing manual subcomponent composition.
* Simplified notification filter UI by replacing nested select
subcomponents with a declarative items prop.

* **Bug Fixes**
* Improved dropdown and select item handling, including disabled states,
separators, and grouped options.

* **Style**
* Enhanced visual consistency and spacing in documentation and UI
components.
  * Updated component classes for better appearance and usability.

* **Chores**
* Upgraded `@jsonforms` dependencies across all packages to version
`^3.6.0`.
  * Improved test and mock setups for new component structures.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: mdatelle <mike@datelle.net>
Co-authored-by: Eli Bosley <ekbosley@gmail.com>
2025-07-03 16:40:06 -04:00
Pujit Mehrotra
0ec0de982f fix(connect): fatal race-condition in websocket disposal (#1462)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved error handling during client shutdown to prevent unhandled
exceptions and ensure smoother cleanup.
* Optimized identity state change detection to avoid redundant event
emissions, reducing unnecessary updates when no actual changes occur.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210701591479200
2025-07-03 13:47:48 -04:00
Eli Bosley
a2807864ac fix: lanip copy button not present (#1459) 2025-07-03 12:59:41 -04:00
Eli Bosley
f88400eea8 fix: pin ranges (#1460)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Updated dependency management settings to pin exact versions during
updates.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-03 10:02:34 -04:00
Pujit Mehrotra
0d443de20e refactor(connect): organize src by concern instead of artifact (#1457)
Reorganizes files, but keeps logic (and Nest dependency relationships)
unchanged.

* **Documentation**
  * Update README to reflect the new directory structure.

* **Refactor**
* Update import paths to match the new feature-based directory
structure.
* Rename `SystemModule` to `NetworkModule` for smaller scope and
increased clarity.
  * Reorganize source code into directories of feature-related concerns.
 
* **Chores**
* Delete unused demo configuration and related code for a cleaner
codebase.

* **Other**
  * No functional changes to end-user features or behaviors.
2025-07-03 09:47:31 -04:00
Pujit Mehrotra
27b33f0f95 build: fix artifact retreival in plugin promotion workflow (#1458)
Tested via manual dispatch on #1456 via cli. results in:
```xml
<!DOCTYPE PLUGIN [
  <!ENTITY name "dynamix.unraid.net">
  <!ENTITY launch "Connect">
  <!ENTITY author "limetech">
  <!ENTITY version "2025.07.03.0623">
  <!ENTITY plugin_url "https://preview.dl.unraid.net/unraid-api/dynamix.unraid.net.plg">
  <!ENTITY source "/boot/config/plugins/dynamix.my.servers/&txz_name;">
  <!ENTITY txz_sha256 "2075cdb8206733f7f037fefdb004a2d719498d6d6d7f3872afd0682a40ceff28">
  <!ENTITY txz_url "https://preview.dl.unraid.net/unraid-api/tag/PR1456/dynamix.unraid.net-4.8.0-x86_64-24.txz">
  <!ENTITY txz_name "dynamix.unraid.net-4.8.0-x86_64-24.txz">
  <!ENTITY arch "x86_64">
  <!ENTITY build "24">
  <!ENTITY tag "PR1456">
  <!ENTITY api_version "4.8.0">
]>
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
  * Updated workflow input descriptions for consistency.
  * Expanded job permissions to improve workflow capabilities.
  * Enhanced artifact download step with additional input options.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-03 09:31:00 -04:00
Pujit Mehrotra
13bd9bb567 fix: pr plugin promotion workflow (#1456)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
  * Enhanced workflow to allow manual triggering with custom inputs.
* Improved artifact handling and plugin file discovery for greater
flexibility and reliability.
* Added better error logging for missing plugin files during workflow
execution.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-02 16:05:18 -04:00
Pujit Mehrotra
f542c8e0bd fix: parsing of ssoEnabled in state.php (#1455)
read `ssoSubIds` in state.php from `api.json`

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
  * Added a new query to check if Single Sign-On (SSO) is enabled.
* Updated UI components to dynamically reflect SSO availability via live
data.
* **Refactor**
* Streamlined internal handling of SSO status detection for improved
reliability and maintainability.
* **Tests**
* Enhanced tests for SSO button behavior with mocked live data and added
edge case coverage for SSO callback handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-02 10:24:38 -04:00
Pujit Mehrotra
038c582aed fix: flash backup integration with Unraid Connect config (#1448)
read `username` from connect.json & drop minigraphConnected check

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210592838407162

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved reliability of configuration file handling for backup and API
features.
* Resolved potential false negatives when checking connection status by
updating connection verification logic.

* **Chores**
  * Centralized configuration paths for easier future updates.
  * Minor formatting improvements for better readability.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-02 10:09:58 -04:00
Pujit Mehrotra
b9a1b9b087 fix(api): connect config email validation (#1454)
Followup to #1451

Empty string in email field of connect.json caused validation error on
load.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
  * Added a file-watching script to streamline development workflows.
* Introduced comprehensive property-based and randomized tests for
configuration parsing, migration, and validation.

* **Bug Fixes**
* Improved handling and validation of configuration fields, including
stricter email validation and robust handling of optional fields.

* **Refactor**
* Updated configuration change detection to buffer events for improved
performance.
* Made minor formatting and visibility adjustments for clarity and
maintainability.

* **Chores**
  * Added new development dependencies for testing and data generation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-02 10:07:27 -04:00
Eli Bosley
d08fc94afb fix: sign out correctly on error (#1452)
This actually doesn't fix the error but should make it more flexible.
Also adds some testing.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary by CodeRabbit

* **Refactor**
* Enhanced error detection for invalid API key messages to improve
accuracy.
* **Tests**
* Added comprehensive tests verifying error handling and client
lifecycle behavior without network dependencies.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-02 10:06:51 -04:00
Eli Bosley
7c6f02a5cb fix: allow rclone to fail to initialize (#1453)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
  * Added a way for users to check if the RClone service is initialized.

* **Bug Fixes**
* Improved error handling and logging for RClone service initialization
and connection checks, providing clearer and more informative messages
if the RClone binary is missing or if connection issues occur.
* Skipped loading provider information when the RClone service is not
initialized, preventing unnecessary errors and warnings.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-02 10:06:30 -04:00
Pujit Mehrotra
ffb2ac51a4 refactor: rm unused oauth token fields in connect model (#1451)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Updated theme settings now allow header background and primary text
colors to be optionally unset or left blank.

* **Bug Fixes**
* Removed unused authentication token fields from sign-in and
configuration forms for a streamlined user experience.

* **Style**
* Improved formatting and readability in several areas of the
application and tests.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-02 09:48:32 -04:00
Pujit Mehrotra
719f460016 fix: error logs from cloud query when connect is not installed (#1450)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Introduced a separate cloud state query, allowing cloud-related data
to be fetched independently from server state data.

* **Improvements**
* Server and cloud state queries are now managed separately, improving
data handling and refresh logic.
* Theme header color fields are now optional and can be unset, offering
greater flexibility for customization.

* **Bug Fixes**
* Enhanced error handling and data updates for cloud and server state
queries.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-02 09:44:31 -04:00
Pujit Mehrotra
3cfe9fe9ee build: replace hash with build increment in slackware txz pkg (#1449)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Introduced support for specifying and propagating a build number
throughout the build process, including command-line options and
workflow inputs.
* TXZ package naming and URLs now include the build number for improved
traceability.

* **Improvements**
* Enhanced robustness in locating TXZ files with improved fallback
logic, especially in CI environments.
* Improved flexibility and validation of environment schema for plugin
builds.

* **Style**
  * Minor formatting corrections for consistency and readability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210677942019563
2025-07-01 10:57:39 -04:00
Eli Bosley
e539d7f603 chore: remove rclone (#1447)
since unraid will ship with it natively, starting at 7.2.

rclone support is not planned for earlier releases.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Removed an unnecessary step from the build process, streamlining
operations.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-30 11:00:34 -04:00
Pujit Mehrotra
a8566e9e5a build: fix doinst.sh compatibility with installpkg --root (#1446)
- Isolate plugin concerns into `.plg` plugin & api file modifiers instead of the api's
slackware package.

## Summary by CodeRabbit

* **New Features**
* Installation process modularized into package installation,
post-install setup with verification, and service startup with cleanup.
* Added logging and error detection during installation, including
symlink verification.
  * Created required log directory to support service dependencies.
* Integrated nginx service with reload capability triggered by
configuration changes.
* Added automatic patching of nginx configuration and hosts file to
improve security and iframe compatibility.
* Enhanced file modification system to handle side effects and trigger
nginx reloads as needed.

* **Refactor**
* Restructured installation scripts for clarity; setup scripts now
separate steps.
  * Removed legacy installation logic and deprecated related scripts.
  * Enabled hard link addition during package creation.
* Simplified installation scripts by removing conditional branching and
detailed logging.
* Streamlined API environment setup by removing redundant post-install
steps.
* Updated dependency injection to explicitly provide nginx service
token.
  * Improved patch application error reporting with file path details.

* **Chores**
  * Disabled legacy scripts to streamline installation.
  * Removed `.gitignore` to track previously ignored files.
* Updated tests to include new dependencies and relaxed logger
assertions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210661184127051
2025-06-30 10:49:46 -04:00
Pujit Mehrotra
f73e5e0058 fix(ui): notifications positioning regression (#1445)
Downgrades the `vue-sonner` dependency from `2.0.0` to `1.3.0` because
the newer version relies on unocss under the hood, which can't pipe
across the web component build/boundary without modifying our css
plumbing.

The older version relied on a `styles.css` stylesheet. That stylesheet
also couldn't make it through our build pipeline, but since it was a
single asset, I vendored it via `sonner.css`.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved logic to prevent duplicate insertion of the toaster element
in the page layout.

* **Chores**
  * Downgraded the "vue-sonner" dependency to version ^1.3.0.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210640791480730
2025-06-27 13:33:25 -04:00
Pujit Mehrotra
64ccea2a81 chore: add type-check step to test-api github workflow (#1443)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
  * Added a type checking step to the automated workflow.
* Improved formatting in the workflow configuration for better
readability.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-26 16:35:45 -04:00
Eli Bosley
86bea56272 feat: move api key fetching to use api key service (#1439)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Refactor**
- Simplified and streamlined the management of the local Connect API
key, renaming it to "ConnectInternal" and removing legacy keys.
- Updated internal logic to directly retrieve or create the Connect API
key without storing or emitting it in configuration or events.
- Replaced custom WebSocket handling with default implementation and
improved asynchronous API key retrieval for client connections.
- Enhanced asynchronous handling for subscription and query execution to
ensure proper client initialization.

- **Chores**
- Removed obsolete methods and test suites related to previous Connect
API key management logic.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-26 16:29:49 -04:00
Pujit Mehrotra
af6e56de60 test: fix connect plugin tests (#1441)
## Summary by CodeRabbit

* **Bug Fixes**
* Improved error handling to prevent runtime exceptions when certain
configuration fields are undefined.
  * Updated test expectations to reflect new error handling behaviors.

* **Refactor**
* Streamlined and modularized the legacy configuration migration process
for better maintainability.
* Removed obsolete configuration fields and related validation from the
configuration model.

* **Tests**
* Added and enhanced test suites to verify configuration migration,
parsing, and URL resolution logic.
* Improved test coverage and robustness with expanded mock data and
flexible assertions.

* **Chores**
* Updated test scripts and dependencies for improved reliability and
compatibility.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-26 15:04:26 -04:00
Pujit Mehrotra
c4c99843c7 fix: config migration from myservers.cfg (#1440)
## Summary by CodeRabbit

- **Bug Fixes**
- Improved handling and migration of legacy configuration values for
smoother upgrades and more accurate settings conversion.

- **Refactor**
- Streamlined the legacy configuration migration process for better
reliability and maintainability.
  - Removed the unused `ssoSubIds` property from configuration models.

- **Tests**
- Added comprehensive tests to ensure correct migration and conversion
of legacy configuration data.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-26 15:00:24 -04:00
Pujit Mehrotra
3122bdb953 fix: api pnpm type-check (#1442)
## Summary by CodeRabbit

* **Tests**
* Updated tests for API key creation by removing unnecessary properties
from input objects.

* **Documentation**
* Added detailed comments explaining type compatibility issues and error
suppression for Fastify plugins.

* **Refactor**
* Made internal validation flags optional in API key input handling to
streamline input validation.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-26 11:12:54 -04:00
Eli Bosley
22fe91cd56 fix: delete legacy connect keys and ensure description 2025-06-25 16:19:09 -04:00
Eli Bosley
b7c2407840 feat: fix shading in UPC to be less severe (#1438)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Style**
- Updated the banner gradient to match the full width of its container.
- Extended the gradient effect for a smoother visual transition across
the banner.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-25 15:26:08 -04:00
Pujit Mehrotra
17b7428779 fix: incorrect state merging in redux store (#1437)
omit stale config entries while merging in new config state

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Refactor**
- Improved state update handling across several modules to enhance
performance and maintain consistency without impacting user experience.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210628784568830
2025-06-25 14:51:01 -04:00
Pujit Mehrotra
a7ef06ea25 fix: backport unraid/webgui#2269 rc.nginx update (#1436)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Enhanced remote access detection for nginx using updated configuration
and plugin integration.
- Introduced a comprehensive Nginx management script tailored for Unraid
OS with SSL handling, server lifecycle controls, and dynamic
configuration.
- **Bug Fixes**
- Improved script robustness by fixing shell loop syntax for proper
handling of array keys.
- **Chores**
  - Added compatibility patches for Unraid versions before 7.2.0.
  - Updated test suites to include new nginx script modifications.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-25 12:58:28 -04:00
Pujit Mehrotra
5ba4479663 chore: rm obsolete style block from myservers1.php (#1435)
Complement to https://github.com/unraid/webgui/pull/2270

Compared our dynamix.my.servers with the webgui's and made the
corresponding changes. activation code logic was omitted because it has
already been written into the api.

python script used for comparison:
https://gist.github.com/pujitm/43a4d2fc35c74f51c70cc66fe1909e6c
```py
#!/usr/bin/env python3
"""
Directory comparison script that recursively compares two directories
and shows files that exist in one but not the other, plus diffs for common files.
"""

import os
import sys
import subprocess
from pathlib import Path
from typing import Set, Tuple


def get_all_files(directory: str) -> Set[str]:
    """Get all files in a directory recursively, returning relative paths."""
    files = set()
    dir_path = Path(directory)
    
    if not dir_path.exists():
        print(f"Error: Directory '{directory}' does not exist")
        return files
    
    for root, dirs, filenames in os.walk(directory):
        for filename in filenames:
            full_path = Path(root) / filename
            # Get relative path from the base directory
            relative_path = full_path.relative_to(dir_path)
            files.add(str(relative_path))
    
    return files


def compare_directories(dir1: str, dir2: str) -> Tuple[Set[str], Set[str], Set[str]]:
    """
    Compare two directories and return files in each directory.
    
    Returns:
        - files only in dir1
        - files only in dir2  
        - files in both directories
    """
    files1 = get_all_files(dir1)
    files2 = get_all_files(dir2)
    
    only_in_dir1 = files1 - files2
    only_in_dir2 = files2 - files1
    in_both = files1 & files2
    
    return only_in_dir1, only_in_dir2, in_both


def run_diff(file1_path: str, file2_path: str, relative_path: str) -> bool:
    """
    Run diff on two files and print the output.
    Returns True if files are different, False if identical.
    """
    try:
        # Use diff -u for unified diff format
        result = subprocess.run(
            ['diff', '-u', file1_path, file2_path],
            capture_output=True,
            text=True
        )
        
        if result.returncode == 0:
            # Files are identical
            return False
        elif result.returncode == 1:
            # Files are different
            print(f"\n--- Diff for: {relative_path} ---")
            print(result.stdout)
            return True
        else:
            # Error occurred
            print(f"\nError running diff on {relative_path}: {result.stderr}")
            return False
            
    except FileNotFoundError:
        print(f"\nError: 'diff' command not found. Please install diffutils.")
        return False
    except Exception as e:
        print(f"\nError comparing {relative_path}: {e}")
        return False


def compare_file_contents(dir1: str, dir2: str, common_files: Set[str]) -> Tuple[int, int]:
    """
    Compare contents of files that exist in both directories.
    Returns (identical_count, different_count).
    """
    identical_count = 0
    different_count = 0
    
    print(f"\nComparing contents of {len(common_files)} common files...")
    print("=" * 60)
    
    for relative_path in sorted(common_files):
        file1_path = os.path.join(dir1, relative_path)
        file2_path = os.path.join(dir2, relative_path)
        
        if run_diff(file1_path, file2_path, relative_path):
            different_count += 1
        else:
            identical_count += 1
    
    return identical_count, different_count


def main():
    if len(sys.argv) < 3:
        print("Usage: python compare_directories.py <directory1> <directory2> [--no-diff]")
        print("Example: python compare_directories.py /path/to/dir1 /path/to/dir2")
        print("Use --no-diff to skip content comparison")
        sys.exit(1)
    
    dir1 = sys.argv[1]
    dir2 = sys.argv[2]
    skip_diff = '--no-diff' in sys.argv
    
    print(f"Comparing directories:")
    print(f"  Directory 1: {dir1}")
    print(f"  Directory 2: {dir2}")
    print("=" * 60)
    
    only_in_dir1, only_in_dir2, in_both = compare_directories(dir1, dir2)
    
    print(f"\nFiles only in '{dir1}' ({len(only_in_dir1)} files):")
    if only_in_dir1:
        for file in sorted(only_in_dir1):
            print(f"  - {file}")
    else:
        print("  (none)")
    
    print(f"\nFiles only in '{dir2}' ({len(only_in_dir2)} files):")
    if only_in_dir2:
        for file in sorted(only_in_dir2):
            print(f"  - {file}")
    else:
        print("  (none)")
    
    print(f"\nFiles in both directories ({len(in_both)} files):")
    if in_both:
        for file in sorted(in_both):
            print(f"  - {file}")
    else:
        print("  (none)")
    
    # Compare file contents if requested and there are common files
    identical_count = 0
    different_count = 0
    if not skip_diff and in_both:
        identical_count, different_count = compare_file_contents(dir1, dir2, in_both)
    
    print("\n" + "=" * 60)
    print(f"Summary:")
    print(f"  Total files in '{dir1}': {len(only_in_dir1) + len(in_both)}")
    print(f"  Total files in '{dir2}': {len(only_in_dir2) + len(in_both)}")
    print(f"  Files only in '{dir1}': {len(only_in_dir1)}")
    print(f"  Files only in '{dir2}': {len(only_in_dir2)}")
    print(f"  Files in both: {len(in_both)}")
    
    if not skip_diff and in_both:
        print(f"  Identical files: {identical_count}")
        print(f"  Different files: {different_count}")


if __name__ == "__main__":
    main() 
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Added support for extracting and displaying activation code data,
including partner information and logos, when relevant.
- **Style**
- Removed embedded CSS styling from the server management interface
header.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-25 12:57:48 -04:00
Pujit Mehrotra
7bc583b186 fix: remote access lifecycle during boot & shutdown (#1422)
## Summary

- **New Features**
- Introduced a comprehensive Nginx control script for Unraid OS,
enabling advanced server management, SSL certificate handling, and
dynamic configuration based on system state.
https://github.com/unraid/webgui/pull/2269
- Added a utility function to safely execute code with error handling
support.

- **Improvements**
- Enhanced logging across remote access, WAN access, and settings
services for improved traceability.
- Added initialization and cleanup hooks to remote access and UPnP
services for better lifecycle management.
- Optimized configuration persistence by batching rapid changes for more
efficient updates.
- Refined URL resolution logic for improved configuration retrieval and
error handling.
  - Broadened pattern matching for domain keys in Nginx state parsing.
- Updated remote access settings to reload the network stack after
changes.
- Simplified remote access and WAN port configuration logic for clarity
and accuracy.
- Improved port mapping logic with explicit error handling in UPnP
service.
- Updated UI and form controls for remote access settings to reflect SSL
requirements and access type restrictions.

- **Configuration**
  - Updated the default path for module configuration files.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-24 15:10:07 -04:00
Eli Bosley
b8035c207a feat: move to cron v4 (#1428)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Chores**
- Updated internal dependencies for improved compatibility and
performance.
- Adjusted package configuration to include an additional built
dependency.

- **Bug Fixes**
- Improved the accuracy of task status reporting in the UPNP job
manager.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-20 17:32:12 -04:00
Eli Bosley
1b279bbab3 feat: info resolver cleanup (#1425)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Introduced device information endpoints, allowing users to query GPU,
PCI, and USB device details.
- Added new system information endpoints for apps, OS, CPU, display,
versions, and memory, providing detailed environment insights.
- Added a new configuration file for network and authentication
settings.

- **Bug Fixes**
- Improved error handling for system and device information retrieval,
ensuring graceful fallbacks when data is unavailable.

- **Tests**
- Added comprehensive tests for device and system information services
and resolvers to ensure accurate data and robust error handling.

- **Refactor**
- Refactored system information and display logic into dedicated service
classes for better maintainability and modularity.
- Updated resolvers to delegate data fetching to injected services
instead of standalone functions or inline logic.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-06-20 17:22:54 -04:00
renovate[bot]
68df344a4b fix(deps): update all non-major dependencies (#1399)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence | Type |
Update |
|---|---|---|---|---|---|---|---|
| [lucide-vue-next](https://lucide.dev)
([source](https://redirect.github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-vue-next))
| [`^0.511.0` ->
`^0.519.0`](https://renovatebot.com/diffs/npm/lucide-vue-next/0.511.0/0.519.0)
|
[![age](https://developer.mend.io/api/mc/badges/age/npm/lucide-vue-next/0.519.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/lucide-vue-next/0.519.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/lucide-vue-next/0.511.0/0.519.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/lucide-vue-next/0.511.0/0.519.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
| dependencies | minor |
| [node](https://nodejs.org)
([source](https://redirect.github.com/nodejs/node)) | `22.15.1` ->
`22.16.0` |
[![age](https://developer.mend.io/api/mc/badges/age/node-version/node/v22.16.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/node-version/node/v22.16.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/node-version/node/v22.15.1/v22.16.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/node-version/node/v22.15.1/v22.16.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
| | minor |
| [pnpm](https://pnpm.io)
([source](https://redirect.github.com/pnpm/pnpm/tree/HEAD/pnpm)) |
[`10.11.0` ->
`10.12.1`](https://renovatebot.com/diffs/npm/pnpm/10.11.0/10.12.1) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/pnpm/10.12.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/pnpm/10.12.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/pnpm/10.11.0/10.12.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/pnpm/10.11.0/10.12.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
| packageManager | minor |
|
[vuetify-nuxt-module](https://redirect.github.com/vuetifyjs/nuxt-module)
| [`0.18.6` ->
`0.18.7`](https://renovatebot.com/diffs/npm/vuetify-nuxt-module/0.18.6/0.18.7)
|
[![age](https://developer.mend.io/api/mc/badges/age/npm/vuetify-nuxt-module/0.18.7?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/vuetify-nuxt-module/0.18.7?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/vuetify-nuxt-module/0.18.6/0.18.7?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/vuetify-nuxt-module/0.18.6/0.18.7?slim=true)](https://docs.renovatebot.com/merge-confidence/)
| devDependencies | patch |

---

### Release Notes

<details>
<summary>lucide-icons/lucide (lucide-vue-next)</summary>

###
[`v0.519.0`](https://redirect.github.com/lucide-icons/lucide/compare/0.518.0...0.519.0)

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.518.0...0.519.0)

###
[`v0.518.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.518.0):
Version 0.518.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.517.0...0.518.0)

#### What's Changed

- fix(icons): updated `egg` and `egg-off` icons by
[@&#8203;jamiemlaw](https://redirect.github.com/jamiemlaw) in
[https://github.com/lucide-icons/lucide/pull/3299](https://redirect.github.com/lucide-icons/lucide/pull/3299)
- fix(icons): renamed `*-help` and `*-question` icons to
`*-question-mark` by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/2540](https://redirect.github.com/lucide-icons/lucide/pull/2540)
- chore(scripts): Refactor scripts to typescript by
[@&#8203;ericfennis](https://redirect.github.com/ericfennis) in
[https://github.com/lucide-icons/lucide/pull/3316](https://redirect.github.com/lucide-icons/lucide/pull/3316)
- feat(icons): added `drone` icon by
[@&#8203;shopped](https://redirect.github.com/shopped) in
[https://github.com/lucide-icons/lucide/pull/3247](https://redirect.github.com/lucide-icons/lucide/pull/3247)

#### New Contributors

- [@&#8203;shopped](https://redirect.github.com/shopped) made their
first contribution in
[https://github.com/lucide-icons/lucide/pull/3247](https://redirect.github.com/lucide-icons/lucide/pull/3247)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.517.0...0.518.0

###
[`v0.517.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.517.0):
Version 0.517.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.516.0...0.517.0)

#### What's Changed

- feat(icons): adds `barrel` icon by
[@&#8203;karsa-mistmere](https://redirect.github.com/karsa-mistmere) in
[https://github.com/lucide-icons/lucide/pull/1955](https://redirect.github.com/lucide-icons/lucide/pull/1955)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.516.0...0.517.0

###
[`v0.516.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.516.0):
Version 0.516.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.515.0...0.516.0)

#### What's Changed

- fix(icons): changed `stamp` icon by
[@&#8203;jamiemlaw](https://redirect.github.com/jamiemlaw) in
[https://github.com/lucide-icons/lucide/pull/3310](https://redirect.github.com/lucide-icons/lucide/pull/3310)
- fix(icons): changed `pocket` icon by
[@&#8203;jamiemlaw](https://redirect.github.com/jamiemlaw) in
[https://github.com/lucide-icons/lucide/pull/3304](https://redirect.github.com/lucide-icons/lucide/pull/3304)
- fix(icons): changed `mic` icon by
[@&#8203;jamiemlaw](https://redirect.github.com/jamiemlaw) in
[https://github.com/lucide-icons/lucide/pull/3301](https://redirect.github.com/lucide-icons/lucide/pull/3301)
- fix(icons): changed `radio` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3293](https://redirect.github.com/lucide-icons/lucide/pull/3293)
- fix: some typos for categories by
[@&#8203;npv12](https://redirect.github.com/npv12) in
[https://github.com/lucide-icons/lucide/pull/3319](https://redirect.github.com/lucide-icons/lucide/pull/3319)
- perf(docs): optimize IconsOverview initial render - 50% faster load
times by
[@&#8203;epifaniofrancisco](https://redirect.github.com/epifaniofrancisco)
in
[https://github.com/lucide-icons/lucide/pull/3282](https://redirect.github.com/lucide-icons/lucide/pull/3282)
- fix(docs): remove flex-direction CSS causing absolute stroke width
toggle positioning issue
([#&#8203;3308](https://redirect.github.com/lucide-icons/lucide/issues/3308))
by
[@&#8203;epifaniofrancisco](https://redirect.github.com/epifaniofrancisco)
in
[https://github.com/lucide-icons/lucide/pull/3317](https://redirect.github.com/lucide-icons/lucide/pull/3317)
- feat(icons): added `wifi-cog` icon by
[@&#8203;luisdlopera](https://redirect.github.com/luisdlopera) in
[https://github.com/lucide-icons/lucide/pull/3133](https://redirect.github.com/lucide-icons/lucide/pull/3133)

#### New Contributors

- [@&#8203;npv12](https://redirect.github.com/npv12) made their first
contribution in
[https://github.com/lucide-icons/lucide/pull/3319](https://redirect.github.com/lucide-icons/lucide/pull/3319)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.515.0...0.516.0

###
[`v0.515.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.515.0):
Version 0.515.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.514.0...0.515.0)

#### What's Changed

- fix(icons): changed `house-plus` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3238](https://redirect.github.com/lucide-icons/lucide/pull/3238)
- fix(icons): changed `radiation` icon by
[@&#8203;jamiemlaw](https://redirect.github.com/jamiemlaw) in
[https://github.com/lucide-icons/lucide/pull/3303](https://redirect.github.com/lucide-icons/lucide/pull/3303)
- feat(icons): added `rectangle-circle` icon by
[@&#8203;zefir-git](https://redirect.github.com/zefir-git) in
[https://github.com/lucide-icons/lucide/pull/3245](https://redirect.github.com/lucide-icons/lucide/pull/3245)

#### New Contributors

- [@&#8203;zefir-git](https://redirect.github.com/zefir-git) made their
first contribution in
[https://github.com/lucide-icons/lucide/pull/3245](https://redirect.github.com/lucide-icons/lucide/pull/3245)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.514.0...0.515.0

###
[`v0.514.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.514.0):
Version 0.514.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.513.0...0.514.0)

#### What's Changed

- fix(icons): changed `trophy` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/2475](https://redirect.github.com/lucide-icons/lucide/pull/2475)
- fix(pull-request-icon-preview): pinned and --forced svgson installati…
by [@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3289](https://redirect.github.com/lucide-icons/lucide/pull/3289)
- chore(metadata): added tag to `bandage` icon by
[@&#8203;jamiemlaw](https://redirect.github.com/jamiemlaw) in
[https://github.com/lucide-icons/lucide/pull/3300](https://redirect.github.com/lucide-icons/lucide/pull/3300)
- fix(icons): changed `settings-2` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/2974](https://redirect.github.com/lucide-icons/lucide/pull/2974)
- fix(docs):
[#&#8203;2984](https://redirect.github.com/lucide-icons/lucide/issues/2984)
absoluteStrokeWidth not resetting with Reset button by
[@&#8203;epifaniofrancisco](https://redirect.github.com/epifaniofrancisco)
in
[https://github.com/lucide-icons/lucide/pull/3261](https://redirect.github.com/lucide-icons/lucide/pull/3261)
- feat(icons): added book-alert icon by
[@&#8203;domasmark](https://redirect.github.com/domasmark) in
[https://github.com/lucide-icons/lucide/pull/3249](https://redirect.github.com/lucide-icons/lucide/pull/3249)

#### New Contributors

- [@&#8203;domasmark](https://redirect.github.com/domasmark) made their
first contribution in
[https://github.com/lucide-icons/lucide/pull/3249](https://redirect.github.com/lucide-icons/lucide/pull/3249)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.513.0...0.514.0

###
[`v0.513.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.513.0):
Version 0.513.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.512.0...0.513.0)

#### What's Changed

- feat(icons): Add sim card icon from lab by
[@&#8203;ericfennis](https://redirect.github.com/ericfennis) in
[https://github.com/lucide-icons/lucide/pull/3275](https://redirect.github.com/lucide-icons/lucide/pull/3275)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.512.0...0.513.0

###
[`v0.512.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.512.0):
Version 0.512.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.511.0...0.512.0)

#### What's Changed

- feat(icons): added `circle-pound-sterling` icon by
[@&#8203;lieonlion](https://redirect.github.com/lieonlion) in
[https://github.com/lucide-icons/lucide/pull/2822](https://redirect.github.com/lucide-icons/lucide/pull/2822)
- build(deps-dev): bump vite from 6.3.2 to 6.3.4 by
[@&#8203;dependabot](https://redirect.github.com/dependabot) in
[https://github.com/lucide-icons/lucide/pull/3181](https://redirect.github.com/lucide-icons/lucide/pull/3181)
- docs(docs): added testing website locally instructions by
[@&#8203;briz123](https://redirect.github.com/briz123) in
[https://github.com/lucide-icons/lucide/pull/3124](https://redirect.github.com/lucide-icons/lucide/pull/3124)
- build(deps-dev): bump vite from 6.0.7 to 6.1.6 by
[@&#8203;dependabot](https://redirect.github.com/dependabot) in
[https://github.com/lucide-icons/lucide/pull/3236](https://redirect.github.com/lucide-icons/lucide/pull/3236)
- fix(icons): changed `square-check-big` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3156](https://redirect.github.com/lucide-icons/lucide/pull/3156)
- fix(icons): changed `list-collapse` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3081](https://redirect.github.com/lucide-icons/lucide/pull/3081)
- fix(icons): changed `battery-*` icons by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3083](https://redirect.github.com/lucide-icons/lucide/pull/3083)
- fix(icons): changed `paperclip` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/2956](https://redirect.github.com/lucide-icons/lucide/pull/2956)
- fix(icons): changed `eraser` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3076](https://redirect.github.com/lucide-icons/lucide/pull/3076)
- feat(icons): Add `cloud-check` icon by
[@&#8203;lscheibel](https://redirect.github.com/lscheibel) in
[https://github.com/lucide-icons/lucide/pull/2612](https://redirect.github.com/lucide-icons/lucide/pull/2612)
- feat(icon): add `id-card-lanyard` icon by
[@&#8203;python2911](https://redirect.github.com/python2911) in
[https://github.com/lucide-icons/lucide/pull/2898](https://redirect.github.com/lucide-icons/lucide/pull/2898)
- feat(angular): update peer dependencies for Angular to support version
20.x by
[@&#8203;JeevanMahesha](https://redirect.github.com/JeevanMahesha) in
[https://github.com/lucide-icons/lucide/pull/3273](https://redirect.github.com/lucide-icons/lucide/pull/3273)
- fix(icons): changed `file-badge` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/2934](https://redirect.github.com/lucide-icons/lucide/pull/2934)
- feat(icons): added `grid-3x2` icon by
[@&#8203;qubrat](https://redirect.github.com/qubrat) in
[https://github.com/lucide-icons/lucide/pull/3216](https://redirect.github.com/lucide-icons/lucide/pull/3216)

#### New Contributors

- [@&#8203;lieonlion](https://redirect.github.com/lieonlion) made their
first contribution in
[https://github.com/lucide-icons/lucide/pull/2822](https://redirect.github.com/lucide-icons/lucide/pull/2822)
- [@&#8203;python2911](https://redirect.github.com/python2911) made
their first contribution in
[https://github.com/lucide-icons/lucide/pull/2898](https://redirect.github.com/lucide-icons/lucide/pull/2898)
- [@&#8203;JeevanMahesha](https://redirect.github.com/JeevanMahesha)
made their first contribution in
[https://github.com/lucide-icons/lucide/pull/3273](https://redirect.github.com/lucide-icons/lucide/pull/3273)
- [@&#8203;qubrat](https://redirect.github.com/qubrat) made their first
contribution in
[https://github.com/lucide-icons/lucide/pull/3216](https://redirect.github.com/lucide-icons/lucide/pull/3216)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.511.0...0.512.0

</details>

<details>
<summary>nodejs/node (node)</summary>

###
[`v22.16.0`](https://redirect.github.com/nodejs/node/releases/tag/v22.16.0):
2025-05-21, Version 22.16.0 &#x27;Jod&#x27; (LTS), @&#8203;aduh95

[Compare
Source](https://redirect.github.com/nodejs/node/compare/v22.15.1...v22.16.0)

##### Notable Changes

-
\[[`c3ceaebb7a`](https://redirect.github.com/nodejs/node/commit/c3ceaebb7a)]
- **deps**: update timezone to 2025b (Node.js GitHub Bot)
[#&#8203;57857](https://redirect.github.com/nodejs/node/pull/57857)
-
\[[`5059a746ec`](https://redirect.github.com/nodejs/node/commit/5059a746ec)]
- **doc**: add dario-piotrowicz to collaborators (Dario Piotrowicz)
[#&#8203;58102](https://redirect.github.com/nodejs/node/pull/58102)
-
\[[`c8ceaaf397`](https://redirect.github.com/nodejs/node/commit/c8ceaaf397)]
- **(SEMVER-MINOR)** **doc**: graduate multiple experimental apis (James
M Snell)
[#&#8203;57765](https://redirect.github.com/nodejs/node/pull/57765)
-
\[[`e21b37d9df`](https://redirect.github.com/nodejs/node/commit/e21b37d9df)]
- **(SEMVER-MINOR)** **esm**: graduate import.meta properties (James M
Snell)
[#&#8203;58011](https://redirect.github.com/nodejs/node/pull/58011)
-
\[[`832640c35e`](https://redirect.github.com/nodejs/node/commit/832640c35e)]
- **(SEMVER-MINOR)** **esm**: support top-level Wasm without package
type (Guy Bedford)
[#&#8203;57610](https://redirect.github.com/nodejs/node/pull/57610)
-
\[[`c510391d2f`](https://redirect.github.com/nodejs/node/commit/c510391d2f)]
- **(SEMVER-MINOR)** **sqlite**: add StatementSync.prototype.columns()
(Colin Ihrig)
[#&#8203;57490](https://redirect.github.com/nodejs/node/pull/57490)
-
\[[`5d1230bec0`](https://redirect.github.com/nodejs/node/commit/5d1230bec0)]
- **(SEMVER-MINOR)** **src**: set default config as `node.config.json`
(Marco Ippolito)
[#&#8203;57171](https://redirect.github.com/nodejs/node/pull/57171)
-
\[[`30bb1ccbb0`](https://redirect.github.com/nodejs/node/commit/30bb1ccbb0)]
- **(SEMVER-MINOR)** **src**: create
`THROW_ERR_OPTIONS_BEFORE_BOOTSTRAPPING` (Marco Ippolito)
[#&#8203;57016](https://redirect.github.com/nodejs/node/pull/57016)
-
\[[`0350c6f478`](https://redirect.github.com/nodejs/node/commit/0350c6f478)]
- **(SEMVER-MINOR)** **src**: add config file support (Marco Ippolito)
[#&#8203;57016](https://redirect.github.com/nodejs/node/pull/57016)
-
\[[`e1d3a9e192`](https://redirect.github.com/nodejs/node/commit/e1d3a9e192)]
- **(SEMVER-MINOR)** **src**: add ExecutionAsyncId getter for any
Context (Attila Szegedi)
[#&#8203;57820](https://redirect.github.com/nodejs/node/pull/57820)
-
\[[`0ec912f452`](https://redirect.github.com/nodejs/node/commit/0ec912f452)]
- **(SEMVER-MINOR)** **stream**: preserve AsyncLocalStorage context in
finished() (Gürgün Dayıoğlu)
[#&#8203;57865](https://redirect.github.com/nodejs/node/pull/57865)
-
\[[`43490c8797`](https://redirect.github.com/nodejs/node/commit/43490c8797)]
- **(SEMVER-MINOR)** **util**: add `types.isFloat16Array()` (Livia
Medeiros)
[#&#8203;57879](https://redirect.github.com/nodejs/node/pull/57879)
-
\[[`dda6ca9172`](https://redirect.github.com/nodejs/node/commit/dda6ca9172)]
- **(SEMVER-MINOR)** **worker**: add worker.getHeapStatistics() (Matteo
Collina)
[#&#8203;57888](https://redirect.github.com/nodejs/node/pull/57888)

##### Commits

-
\[[`4252dc798c`](https://redirect.github.com/nodejs/node/commit/4252dc798c)]
- **assert**: support `Float16Array` in loose deep equality checks
(Livia Medeiros)
[#&#8203;57881](https://redirect.github.com/nodejs/node/pull/57881)
-
\[[`1c7396b078`](https://redirect.github.com/nodejs/node/commit/1c7396b078)]
- **assert,util**: fix constructor lookup in deep equal comparison
(Ruben Bridgewater)
[#&#8203;57876](https://redirect.github.com/nodejs/node/pull/57876)
-
\[[`1ded5f25c8`](https://redirect.github.com/nodejs/node/commit/1ded5f25c8)]
- **assert,util**: improve deep object comparison performance (Ruben
Bridgewater)
[#&#8203;57648](https://redirect.github.com/nodejs/node/pull/57648)
-
\[[`696b5f85ca`](https://redirect.github.com/nodejs/node/commit/696b5f85ca)]
- **assert,util**: improve unequal number comparison performance (Ruben
Bridgewater)
[#&#8203;57619](https://redirect.github.com/nodejs/node/pull/57619)
-
\[[`775ee4d40f`](https://redirect.github.com/nodejs/node/commit/775ee4d40f)]
- **assert,util**: improve array comparison (Ruben Bridgewater)
[#&#8203;57619](https://redirect.github.com/nodejs/node/pull/57619)
-
\[[`3766992ba4`](https://redirect.github.com/nodejs/node/commit/3766992ba4)]
- **benchmark**: add sqlite prepare select get (Vinícius Lourenço)
[#&#8203;58040](https://redirect.github.com/nodejs/node/pull/58040)
-
\[[`8390276be3`](https://redirect.github.com/nodejs/node/commit/8390276be3)]
- **benchmark**: add sqlite prepare select all (Vinícius Lourenço)
[#&#8203;58040](https://redirect.github.com/nodejs/node/pull/58040)
-
\[[`6a9b79e5c1`](https://redirect.github.com/nodejs/node/commit/6a9b79e5c1)]
- **benchmark**: add sqlite is transaction (Vinícius Lourenço)
[#&#8203;58040](https://redirect.github.com/nodejs/node/pull/58040)
-
\[[`f689f98344`](https://redirect.github.com/nodejs/node/commit/f689f98344)]
- **benchmark**: add sqlite prepare insert (Vinícius Lourenço)
[#&#8203;58040](https://redirect.github.com/nodejs/node/pull/58040)
-
\[[`14a82804d7`](https://redirect.github.com/nodejs/node/commit/14a82804d7)]
- **benchmark**: disambiguate `filename` and `dirname` read perf
(Antoine du Hamel)
[#&#8203;58056](https://redirect.github.com/nodejs/node/pull/58056)
-
\[[`e7e8256d35`](https://redirect.github.com/nodejs/node/commit/e7e8256d35)]
- **buffer**: avoid creating unnecessary environment (Yagiz Nizipli)
[#&#8203;58053](https://redirect.github.com/nodejs/node/pull/58053)
-
\[[`d7d8e8e994`](https://redirect.github.com/nodejs/node/commit/d7d8e8e994)]
- **buffer**: define global v8::CFunction objects as const (Mert Can
Altin)
[#&#8203;57676](https://redirect.github.com/nodejs/node/pull/57676)
-
\[[`f37633e85a`](https://redirect.github.com/nodejs/node/commit/f37633e85a)]
- **build**: use `$(BUILDTYPE)` when cleaning coverage files (Aviv
Keller)
[#&#8203;57995](https://redirect.github.com/nodejs/node/pull/57995)
-
\[[`e5bf67fe77`](https://redirect.github.com/nodejs/node/commit/e5bf67fe77)]
- **build**: define python when generating `out/Makefile` (Aviv Keller)
[#&#8203;57970](https://redirect.github.com/nodejs/node/pull/57970)
-
\[[`718f874ae0`](https://redirect.github.com/nodejs/node/commit/718f874ae0)]
- **build**: fix zstd libname (Antoine du Hamel)
[#&#8203;57999](https://redirect.github.com/nodejs/node/pull/57999)
-
\[[`53c5fdcae1`](https://redirect.github.com/nodejs/node/commit/53c5fdcae1)]
- **crypto**: fix cross-realm `SharedArrayBuffer` validation (Antoine du
Hamel)
[#&#8203;57974](https://redirect.github.com/nodejs/node/pull/57974)
-
\[[`78f4ffee5d`](https://redirect.github.com/nodejs/node/commit/78f4ffee5d)]
- **crypto**: fix cross-realm check of `ArrayBuffer` (Felipe Forbeck)
[#&#8203;57828](https://redirect.github.com/nodejs/node/pull/57828)
-
\[[`f606352b63`](https://redirect.github.com/nodejs/node/commit/f606352b63)]
- **crypto**: forbid passing `Float16Array` to `getRandomValues()`
(Livia Medeiros)
[#&#8203;57880](https://redirect.github.com/nodejs/node/pull/57880)
-
\[[`23c4e941c2`](https://redirect.github.com/nodejs/node/commit/23c4e941c2)]
- **crypto**: remove BoringSSL dh-primes addition (Shelley Vohr)
[#&#8203;57023](https://redirect.github.com/nodejs/node/pull/57023)
-
\[[`8339d9bc14`](https://redirect.github.com/nodejs/node/commit/8339d9bc14)]
- **deps**: V8: cherry-pick
[`f915fa4`](https://redirect.github.com/nodejs/node/commit/f915fa4c9f41)
(Chengzhong Wu)
[#&#8203;55484](https://redirect.github.com/nodejs/node/pull/55484)
-
\[[`c2111dd126`](https://redirect.github.com/nodejs/node/commit/c2111dd126)]
- **deps**: V8: backport
[`e5dbbba`](https://redirect.github.com/nodejs/node/commit/e5dbbbadcbff)
(Darshan Sen)
[#&#8203;58120](https://redirect.github.com/nodejs/node/pull/58120)
-
\[[`4cc49be951`](https://redirect.github.com/nodejs/node/commit/4cc49be951)]
- **deps**: update zstd to 1.5.7 (Node.js GitHub Bot)
[#&#8203;57940](https://redirect.github.com/nodejs/node/pull/57940)
-
\[[`c956d37c84`](https://redirect.github.com/nodejs/node/commit/c956d37c84)]
- **deps**: update zlib to 1.3.0.1-motley-780819f (Node.js GitHub Bot)
[#&#8203;57768](https://redirect.github.com/nodejs/node/pull/57768)
-
\[[`c3ceaebb7a`](https://redirect.github.com/nodejs/node/commit/c3ceaebb7a)]
- **deps**: update timezone to 2025b (Node.js GitHub Bot)
[#&#8203;57857](https://redirect.github.com/nodejs/node/pull/57857)
-
\[[`b5cd0eb590`](https://redirect.github.com/nodejs/node/commit/b5cd0eb590)]
- **deps**: update simdutf to 6.4.2 (Node.js GitHub Bot)
[#&#8203;57855](https://redirect.github.com/nodejs/node/pull/57855)
-
\[[`3eb6b814e9`](https://redirect.github.com/nodejs/node/commit/3eb6b814e9)]
- **deps**: update simdutf to 6.4.0 (Node.js GitHub Bot)
[#&#8203;56764](https://redirect.github.com/nodejs/node/pull/56764)
-
\[[`0be9fa3218`](https://redirect.github.com/nodejs/node/commit/0be9fa3218)]
- **deps**: update icu to 77.1 (Node.js GitHub Bot)
[#&#8203;57455](https://redirect.github.com/nodejs/node/pull/57455)
-
\[[`d5cf4254fb`](https://redirect.github.com/nodejs/node/commit/d5cf4254fb)]
- **doc**: add HBSPS as triager (Wiyeong Seo)
[#&#8203;57980](https://redirect.github.com/nodejs/node/pull/57980)
-
\[[`ad0861dba0`](https://redirect.github.com/nodejs/node/commit/ad0861dba0)]
- **doc**: add ambassaor message (Brian Muenzenmeyer)
[#&#8203;57600](https://redirect.github.com/nodejs/node/pull/57600)
-
\[[`0d3ec1aafe`](https://redirect.github.com/nodejs/node/commit/0d3ec1aafe)]
- **doc**: fix misaligned options in vm.compileFunction() (Jimmy Leung)
[#&#8203;58145](https://redirect.github.com/nodejs/node/pull/58145)
-
\[[`1f70baf3b0`](https://redirect.github.com/nodejs/node/commit/1f70baf3b0)]
- **doc**: add missing options.signal to
readlinePromises.createInterface() (Jimmy Leung)
[#&#8203;55456](https://redirect.github.com/nodejs/node/pull/55456)
-
\[[`ec6a48621f`](https://redirect.github.com/nodejs/node/commit/ec6a48621f)]
- **doc**: fix typo of file `zlib.md` (yusheng chen)
[#&#8203;58093](https://redirect.github.com/nodejs/node/pull/58093)
-
\[[`37e360e386`](https://redirect.github.com/nodejs/node/commit/37e360e386)]
- **doc**: make stability labels more consistent (Antoine du Hamel)
[#&#8203;57516](https://redirect.github.com/nodejs/node/pull/57516)
-
\[[`2b5d63d36e`](https://redirect.github.com/nodejs/node/commit/2b5d63d36e)]
- **doc**: allow the $schema property in node.config.json (Remco
Haszing)
[#&#8203;57560](https://redirect.github.com/nodejs/node/pull/57560)
-
\[[`a2063638e2`](https://redirect.github.com/nodejs/node/commit/a2063638e2)]
- **doc**: fix `AsyncLocalStorage` example response changes after node
v18 (Naor Tedgi (Abu Emma))
[#&#8203;57969](https://redirect.github.com/nodejs/node/pull/57969)
-
\[[`474c2b14c3`](https://redirect.github.com/nodejs/node/commit/474c2b14c3)]
- **doc**: mark Node.js 18 as End-of-Life (Richard Lau)
[#&#8203;58084](https://redirect.github.com/nodejs/node/pull/58084)
-
\[[`5059a746ec`](https://redirect.github.com/nodejs/node/commit/5059a746ec)]
- **doc**: add dario-piotrowicz to collaborators (Dario Piotrowicz)
[#&#8203;58102](https://redirect.github.com/nodejs/node/pull/58102)
-
\[[`1eec170fc3`](https://redirect.github.com/nodejs/node/commit/1eec170fc3)]
- **doc**: fix formatting of `import.meta.filename` section (Antoine du
Hamel)
[#&#8203;58079](https://redirect.github.com/nodejs/node/pull/58079)
-
\[[`7f108de525`](https://redirect.github.com/nodejs/node/commit/7f108de525)]
- **doc**: fix env variable name in `util.styleText` (Antoine du Hamel)
[#&#8203;58072](https://redirect.github.com/nodejs/node/pull/58072)
-
\[[`54b3f7fffc`](https://redirect.github.com/nodejs/node/commit/54b3f7fffc)]
- **doc**: add returns for https.get (Eng Zer Jun)
[#&#8203;58025](https://redirect.github.com/nodejs/node/pull/58025)
-
\[[`66f2c605a8`](https://redirect.github.com/nodejs/node/commit/66f2c605a8)]
- **doc**: fix typo in `buffer.md` (chocolateboy)
[#&#8203;58052](https://redirect.github.com/nodejs/node/pull/58052)
-
\[[`b0256dd42b`](https://redirect.github.com/nodejs/node/commit/b0256dd42b)]
- **doc**: correct deprecation type of `assert.CallTracker` (René)
[#&#8203;57997](https://redirect.github.com/nodejs/node/pull/57997)
-
\[[`581439c9e6`](https://redirect.github.com/nodejs/node/commit/581439c9e6)]
- **doc**: mark devtools integration section as active development
(Chengzhong Wu)
[#&#8203;57886](https://redirect.github.com/nodejs/node/pull/57886)
-
\[[`a2a2a2f027`](https://redirect.github.com/nodejs/node/commit/a2a2a2f027)]
- **doc**: fix typo in `module.md` (Alex Schwartz)
[#&#8203;57889](https://redirect.github.com/nodejs/node/pull/57889)
-
\[[`c0ec4e2935`](https://redirect.github.com/nodejs/node/commit/c0ec4e2935)]
- **doc**: increase z-index of header element (Dario Piotrowicz)
[#&#8203;57851](https://redirect.github.com/nodejs/node/pull/57851)
-
\[[`93d19ec6cd`](https://redirect.github.com/nodejs/node/commit/93d19ec6cd)]
- **doc**: add missing TS formats for `load` hooks (Antoine du Hamel)
[#&#8203;57837](https://redirect.github.com/nodejs/node/pull/57837)
-
\[[`f5ea06c61f`](https://redirect.github.com/nodejs/node/commit/f5ea06c61f)]
- **doc**: clarify the multi REPL example (Dario Piotrowicz)
[#&#8203;57759](https://redirect.github.com/nodejs/node/pull/57759)
-
\[[`80c4fe1b70`](https://redirect.github.com/nodejs/node/commit/80c4fe1b70)]
- **doc**: fix deprecation type for `DEP0148` (Livia Medeiros)
[#&#8203;57785](https://redirect.github.com/nodejs/node/pull/57785)
-
\[[`01cad99da0`](https://redirect.github.com/nodejs/node/commit/01cad99da0)]
- **doc**: list DOMException as a potential error raised by Node.js
(Chengzhong Wu)
[#&#8203;57783](https://redirect.github.com/nodejs/node/pull/57783)
-
\[[`a08b714a46`](https://redirect.github.com/nodejs/node/commit/a08b714a46)]
- **doc**: add missing v0.x changelog entries (Antoine du Hamel)
[#&#8203;57779](https://redirect.github.com/nodejs/node/pull/57779)
-
\[[`d0b48350fd`](https://redirect.github.com/nodejs/node/commit/d0b48350fd)]
- **doc**: fix typo in writing-docs (Sebastian Beltran)
[#&#8203;57776](https://redirect.github.com/nodejs/node/pull/57776)
-
\[[`bde3725f8b`](https://redirect.github.com/nodejs/node/commit/bde3725f8b)]
- **doc**: clarify examples section in REPL doc (Dario Piotrowicz)
[#&#8203;57762](https://redirect.github.com/nodejs/node/pull/57762)
-
\[[`c8ceaaf397`](https://redirect.github.com/nodejs/node/commit/c8ceaaf397)]
- **(SEMVER-MINOR)** **doc**: graduate multiple experimental apis (James
M Snell)
[#&#8203;57765](https://redirect.github.com/nodejs/node/pull/57765)
-
\[[`92428c2609`](https://redirect.github.com/nodejs/node/commit/92428c2609)]
- **doc**: explicitly state that corepack will be removed in v25+
(Trivikram Kamat)
[#&#8203;57747](https://redirect.github.com/nodejs/node/pull/57747)
-
\[[`298969e1dd`](https://redirect.github.com/nodejs/node/commit/298969e1dd)]
- **doc**: update position type to integer | null in fs (Yukihiro
Hasegawa)
[#&#8203;57745](https://redirect.github.com/nodejs/node/pull/57745)
-
\[[`a9d28e27c9`](https://redirect.github.com/nodejs/node/commit/a9d28e27c9)]
- **doc**: update CI instructions (Antoine du Hamel)
[#&#8203;57743](https://redirect.github.com/nodejs/node/pull/57743)
-
\[[`133d2878a1`](https://redirect.github.com/nodejs/node/commit/133d2878a1)]
- **doc**: update example of using `await` in REPL (Dario Piotrowicz)
[#&#8203;57653](https://redirect.github.com/nodejs/node/pull/57653)
-
\[[`fc5f126629`](https://redirect.github.com/nodejs/node/commit/fc5f126629)]
- **doc**: add back mention of visa fees to onboarding doc (Darshan Sen)
[#&#8203;57730](https://redirect.github.com/nodejs/node/pull/57730)
-
\[[`945f4ac538`](https://redirect.github.com/nodejs/node/commit/945f4ac538)]
- **doc**: process.execve is only unavailable for Windows (Yaksh Bariya)
[#&#8203;57726](https://redirect.github.com/nodejs/node/pull/57726)
-
\[[`f3b885bb5e`](https://redirect.github.com/nodejs/node/commit/f3b885bb5e)]
- **doc**: clarify `unhandledRejection` events behaviors in process doc
(Dario Piotrowicz)
[#&#8203;57654](https://redirect.github.com/nodejs/node/pull/57654)
-
\[[`7326dda5b0`](https://redirect.github.com/nodejs/node/commit/7326dda5b0)]
- **doc**: improved fetch docs (Alessandro Miliucci)
[#&#8203;57296](https://redirect.github.com/nodejs/node/pull/57296)
-
\[[`6906c5eb1f`](https://redirect.github.com/nodejs/node/commit/6906c5eb1f)]
- **doc**: document REPL custom eval arguments (Dario Piotrowicz)
[#&#8203;57690](https://redirect.github.com/nodejs/node/pull/57690)
-
\[[`47a7564e8f`](https://redirect.github.com/nodejs/node/commit/47a7564e8f)]
- **doc**: classify Chrome DevTools Protocol as tier 2 (Chengzhong Wu)
[#&#8203;57634](https://redirect.github.com/nodejs/node/pull/57634)
-
\[[`e274cc1310`](https://redirect.github.com/nodejs/node/commit/e274cc1310)]
- **doc**: replace NOTE that does not render properly (Colin Ihrig)
[#&#8203;57484](https://redirect.github.com/nodejs/node/pull/57484)
-
\[[`bef06b11df`](https://redirect.github.com/nodejs/node/commit/bef06b11df)]
- **esm**: avoid `import.meta` setup costs for unused properties
(Antoine du Hamel)
[#&#8203;57286](https://redirect.github.com/nodejs/node/pull/57286)
-
\[[`e21b37d9df`](https://redirect.github.com/nodejs/node/commit/e21b37d9df)]
- **(SEMVER-MINOR)** **esm**: graduate import.meta properties (James M
Snell)
[#&#8203;58011](https://redirect.github.com/nodejs/node/pull/58011)
-
\[[`832640c35e`](https://redirect.github.com/nodejs/node/commit/832640c35e)]
- **(SEMVER-MINOR)** **esm**: support top-level Wasm without package
type (Guy Bedford)
[#&#8203;57610](https://redirect.github.com/nodejs/node/pull/57610)
-
\[[`8f643471ef`](https://redirect.github.com/nodejs/node/commit/8f643471ef)]
- **fs**: improve globSync performance (Rich Trott)
[#&#8203;57725](https://redirect.github.com/nodejs/node/pull/57725)
-
\[[`bf9e17ecc6`](https://redirect.github.com/nodejs/node/commit/bf9e17ecc6)]
- **http2**: use args.This() instead of args.Holder() (Joyee Cheung)
[#&#8203;58004](https://redirect.github.com/nodejs/node/pull/58004)
-
\[[`137717354f`](https://redirect.github.com/nodejs/node/commit/137717354f)]
- **http2**: fix graceful session close (Kushagra Pandey)
[#&#8203;57808](https://redirect.github.com/nodejs/node/pull/57808)
-
\[[`9baf580269`](https://redirect.github.com/nodejs/node/commit/9baf580269)]
- **http2**: fix check for `frame->hd.type` (hanguanqiang)
[#&#8203;57644](https://redirect.github.com/nodejs/node/pull/57644)
-
\[[`b8189242b2`](https://redirect.github.com/nodejs/node/commit/b8189242b2)]
- **http2**: skip writeHead if stream is closed (Shima Ryuhei)
[#&#8203;57686](https://redirect.github.com/nodejs/node/pull/57686)
-
\[[`4e02a1650a`](https://redirect.github.com/nodejs/node/commit/4e02a1650a)]
- **lib**: remove unused file `fetch_module` (Michaël Zasso)
[#&#8203;55880](https://redirect.github.com/nodejs/node/pull/55880)
-
\[[`d9700fef26`](https://redirect.github.com/nodejs/node/commit/d9700fef26)]
- **lib**: avoid StackOverflow on `serializeError` (Chengzhong Wu)
[#&#8203;58075](https://redirect.github.com/nodejs/node/pull/58075)
-
\[[`f3a16b6d9c`](https://redirect.github.com/nodejs/node/commit/f3a16b6d9c)]
- **lib**: resolve the issue of not adhering to the specified buffer
size (0hm☘️🏳️‍⚧️)
[#&#8203;55896](https://redirect.github.com/nodejs/node/pull/55896)
-
\[[`d4fc282f73`](https://redirect.github.com/nodejs/node/commit/d4fc282f73)]
- **lib**: fix AbortSignal.any() with timeout signals (Gürgün Dayıoğlu)
[#&#8203;57867](https://redirect.github.com/nodejs/node/pull/57867)
-
\[[`f7e2902861`](https://redirect.github.com/nodejs/node/commit/f7e2902861)]
- **lib**: use Map primordial for ActiveAsyncContextFrame (Gürgün
Dayıoğlu)
[#&#8203;57670](https://redirect.github.com/nodejs/node/pull/57670)
-
\[[`8652b0e168`](https://redirect.github.com/nodejs/node/commit/8652b0e168)]
- **meta**: set nodejs/config as codeowner (Marco Ippolito)
[#&#8203;57237](https://redirect.github.com/nodejs/node/pull/57237)
-
\[[`e98504ed95`](https://redirect.github.com/nodejs/node/commit/e98504ed95)]
- **meta**: allow penetration testing on live system with prior
authorization (Matteo Collina)
[#&#8203;57966](https://redirect.github.com/nodejs/node/pull/57966)
-
\[[`340731bea0`](https://redirect.github.com/nodejs/node/commit/340731bea0)]
- **meta**: fix subsystem in commit title (Luigi Pinca)
[#&#8203;57945](https://redirect.github.com/nodejs/node/pull/57945)
-
\[[`d767cbffcf`](https://redirect.github.com/nodejs/node/commit/d767cbffcf)]
- **meta**: bump Mozilla-Actions/sccache-action from 0.0.8 to 0.0.9
(dependabot\[bot])
[#&#8203;57720](https://redirect.github.com/nodejs/node/pull/57720)
-
\[[`575f904b13`](https://redirect.github.com/nodejs/node/commit/575f904b13)]
- **meta**: bump actions/download-artifact from 4.1.9 to 4.2.1
(dependabot\[bot])
[#&#8203;57719](https://redirect.github.com/nodejs/node/pull/57719)
-
\[[`acd323c069`](https://redirect.github.com/nodejs/node/commit/acd323c069)]
- **meta**: bump actions/setup-python from 5.4.0 to 5.5.0
(dependabot\[bot])
[#&#8203;57718](https://redirect.github.com/nodejs/node/pull/57718)
-
\[[`21246fec20`](https://redirect.github.com/nodejs/node/commit/21246fec20)]
- **meta**: bump peter-evans/create-pull-request from 7.0.7 to 7.0.8
(dependabot\[bot])
[#&#8203;57717](https://redirect.github.com/nodejs/node/pull/57717)
-
\[[`97f32d5849`](https://redirect.github.com/nodejs/node/commit/97f32d5849)]
- **meta**: bump github/codeql-action from 3.28.10 to 3.28.13
(dependabot\[bot])
[#&#8203;57716](https://redirect.github.com/nodejs/node/pull/57716)
-
\[[`90ddbb8cfa`](https://redirect.github.com/nodejs/node/commit/90ddbb8cfa)]
- **meta**: bump actions/cache from 4.2.2 to 4.2.3 (dependabot\[bot])
[#&#8203;57715](https://redirect.github.com/nodejs/node/pull/57715)
-
\[[`728425d03e`](https://redirect.github.com/nodejs/node/commit/728425d03e)]
- **meta**: bump actions/setup-node from 4.2.0 to 4.3.0
(dependabot\[bot])
[#&#8203;57714](https://redirect.github.com/nodejs/node/pull/57714)
-
\[[`1f799140e0`](https://redirect.github.com/nodejs/node/commit/1f799140e0)]
- **meta**: bump actions/upload-artifact from 4.6.1 to 4.6.2
(dependabot\[bot])
[#&#8203;57713](https://redirect.github.com/nodejs/node/pull/57713)
-
\[[`021b174a1f`](https://redirect.github.com/nodejs/node/commit/021b174a1f)]
- **module**: tidy code string concat → string templates (Jacob Smith)
[#&#8203;55820](https://redirect.github.com/nodejs/node/pull/55820)
-
\[[`44c5718476`](https://redirect.github.com/nodejs/node/commit/44c5718476)]
- **module**: fix incorrect formatting in require(esm) cycle error
message (haykam821)
[#&#8203;57453](https://redirect.github.com/nodejs/node/pull/57453)
-
\[[`bb09b4d4ae`](https://redirect.github.com/nodejs/node/commit/bb09b4d4ae)]
- **module**: improve `getPackageType` performance (Dario Piotrowicz)
[#&#8203;57599](https://redirect.github.com/nodejs/node/pull/57599)
-
\[[`9e6054e715`](https://redirect.github.com/nodejs/node/commit/9e6054e715)]
- **module**: remove unnecessary `readPackage` function (Dario
Piotrowicz)
[#&#8203;57596](https://redirect.github.com/nodejs/node/pull/57596)
-
\[[`4a8db273ba`](https://redirect.github.com/nodejs/node/commit/4a8db273ba)]
- **node-api**: add nested object wrap and napi_ref test (Chengzhong Wu)
[#&#8203;57981](https://redirect.github.com/nodejs/node/pull/57981)
-
\[[`3c65058f20`](https://redirect.github.com/nodejs/node/commit/3c65058f20)]
- **node-api**: convert NewEnv to node_napi_env\_\_::New (Vladimir
Morozov)
[#&#8203;57834](https://redirect.github.com/nodejs/node/pull/57834)
-
\[[`a4105db1f7`](https://redirect.github.com/nodejs/node/commit/a4105db1f7)]
- **os**: fix netmask format check condition in getCIDR function
(Wiyeong Seo)
[#&#8203;57324](https://redirect.github.com/nodejs/node/pull/57324)
-
\[[`248c938139`](https://redirect.github.com/nodejs/node/commit/248c938139)]
- **process**: disable building execve on IBM i (Abdirahim Musse)
[#&#8203;57883](https://redirect.github.com/nodejs/node/pull/57883)
-
\[[`972275697a`](https://redirect.github.com/nodejs/node/commit/972275697a)]
- **repl**: deprecate `repl.builtinModules` (Dario Piotrowicz)
[#&#8203;57508](https://redirect.github.com/nodejs/node/pull/57508)
-
\[[`7485309d7e`](https://redirect.github.com/nodejs/node/commit/7485309d7e)]
- **sqlite**: add location method (Edy Silva)
[#&#8203;57860](https://redirect.github.com/nodejs/node/pull/57860)
-
\[[`c12cd2a190`](https://redirect.github.com/nodejs/node/commit/c12cd2a190)]
- **sqlite**: add timeout options to DatabaseSync (Edy Silva)
[#&#8203;57752](https://redirect.github.com/nodejs/node/pull/57752)
-
\[[`5e0503a967`](https://redirect.github.com/nodejs/node/commit/5e0503a967)]
- **sqlite**: add setReturnArrays method to StatementSync (Gürgün
Dayıoğlu)
[#&#8203;57542](https://redirect.github.com/nodejs/node/pull/57542)
-
\[[`ed9d2fd51a`](https://redirect.github.com/nodejs/node/commit/ed9d2fd51a)]
- **sqlite**: enable common flags (Edy Silva)
[#&#8203;57621](https://redirect.github.com/nodejs/node/pull/57621)
-
\[[`06dcb318bc`](https://redirect.github.com/nodejs/node/commit/06dcb318bc)]
- **sqlite**: refactor prepared statement iterator (Colin Ihrig)
[#&#8203;57569](https://redirect.github.com/nodejs/node/pull/57569)
-
\[[`c510391d2f`](https://redirect.github.com/nodejs/node/commit/c510391d2f)]
- **(SEMVER-MINOR)** **sqlite**: add StatementSync.prototype.columns()
(Colin Ihrig)
[#&#8203;57490](https://redirect.github.com/nodejs/node/pull/57490)
-
\[[`4e24456a1a`](https://redirect.github.com/nodejs/node/commit/4e24456a1a)]
- **sqlite**: reset statement immediately in run() (Colin Ihrig)
[#&#8203;57350](https://redirect.github.com/nodejs/node/pull/57350)
-
\[[`a9a6891b0b`](https://redirect.github.com/nodejs/node/commit/a9a6891b0b)]
- **sqlite**: fix coverity warnings related to backup() (Colin Ihrig)
[#&#8203;56961](https://redirect.github.com/nodejs/node/pull/56961)
-
\[[`d2e1bcf3d4`](https://redirect.github.com/nodejs/node/commit/d2e1bcf3d4)]
- **sqlite**: fix use-after-free in StatementSync due to premature GC
(Divy Srivastava)
[#&#8203;56840](https://redirect.github.com/nodejs/node/pull/56840)
-
\[[`cfe15ca7b4`](https://redirect.github.com/nodejs/node/commit/cfe15ca7b4)]
- **sqlite**: handle conflicting SQLite and JS errors (Colin Ihrig)
[#&#8203;56787](https://redirect.github.com/nodejs/node/pull/56787)
-
\[[`0e999eb65f`](https://redirect.github.com/nodejs/node/commit/0e999eb65f)]
- **sqlite**: add getter to detect transactions (Colin Ihrig)
[#&#8203;57925](https://redirect.github.com/nodejs/node/pull/57925)
-
\[[`20b27331c0`](https://redirect.github.com/nodejs/node/commit/20b27331c0)]
- **sqlite, test**: expose sqlite online backup api (Edy Silva)
[#&#8203;56253](https://redirect.github.com/nodejs/node/pull/56253)
-
\[[`8856712171`](https://redirect.github.com/nodejs/node/commit/8856712171)]
- **sqlite,doc,test**: add aggregate function (Edy Silva)
[#&#8203;56600](https://redirect.github.com/nodejs/node/pull/56600)
-
\[[`120050db97`](https://redirect.github.com/nodejs/node/commit/120050db97)]
- **sqlite,src**: refactor sqlite value conversion (Edy Silva)
[#&#8203;57571](https://redirect.github.com/nodejs/node/pull/57571)
-
\[[`4c5555d558`](https://redirect.github.com/nodejs/node/commit/4c5555d558)]
- **src**: initialize privateSymbols for per_context (Jason Zhang)
[#&#8203;57479](https://redirect.github.com/nodejs/node/pull/57479)
-
\[[`d2ce9023b1`](https://redirect.github.com/nodejs/node/commit/d2ce9023b1)]
- **src**: ensure primordials are initialized exactly once (Chengzhong
Wu) [#&#8203;57519](https://redirect.github.com/nodejs/node/pull/57519)
-
\[[`06179be6ca`](https://redirect.github.com/nodejs/node/commit/06179be6ca)]
- **src**: disable abseil deadlock detection (Chengzhong Wu)
[#&#8203;57582](https://redirect.github.com/nodejs/node/pull/57582)
-
\[[`5121c47990`](https://redirect.github.com/nodejs/node/commit/5121c47990)]
- **src**: fix node_config_file.h compilation error in GN build (Cheng)
[#&#8203;57210](https://redirect.github.com/nodejs/node/pull/57210)
-
\[[`5d1230bec0`](https://redirect.github.com/nodejs/node/commit/5d1230bec0)]
- **(SEMVER-MINOR)** **src**: set default config as `node.config.json`
(Marco Ippolito)
[#&#8203;57171](https://redirect.github.com/nodejs/node/pull/57171)
-
\[[`ccee741c43`](https://redirect.github.com/nodejs/node/commit/ccee741c43)]
- **src**: namespace config file flags (Marco Ippolito)
[#&#8203;57170](https://redirect.github.com/nodejs/node/pull/57170)
-
\[[`30bb1ccbb0`](https://redirect.github.com/nodejs/node/commit/30bb1ccbb0)]
- **(SEMVER-MINOR)** **src**: create
`THROW_ERR_OPTIONS_BEFORE_BOOTSTRAPPING` (Marco Ippolito)
[#&#8203;57016](https://redirect.github.com/nodejs/node/pull/57016)
-
\[[`0350c6f478`](https://redirect.github.com/nodejs/node/commit/0350c6f478)]
- **(SEMVER-MINOR)** **src**: add config file support (Marco Ippolito)
[#&#8203;57016](https://redirect.github.com/nodejs/node/pull/57016)
-
\[[`eef37d00cb`](https://redirect.github.com/nodejs/node/commit/eef37d00cb)]
- **src**: add more debug logs and comments in NodePlatform (Joyee
Cheung)
[#&#8203;58047](https://redirect.github.com/nodejs/node/pull/58047)
-
\[[`678e8f57c0`](https://redirect.github.com/nodejs/node/commit/678e8f57c0)]
- **src**: add dcheck_eq for Object::New constructor calls (Jonas)
[#&#8203;57943](https://redirect.github.com/nodejs/node/pull/57943)
-
\[[`aee45e2036`](https://redirect.github.com/nodejs/node/commit/aee45e2036)]
- **src**: move windows specific fns to `_WIN32` (Yagiz Nizipli)
[#&#8203;57951](https://redirect.github.com/nodejs/node/pull/57951)
-
\[[`6206a8edbc`](https://redirect.github.com/nodejs/node/commit/6206a8edbc)]
- **src**: improve thread safety of TaskQueue (Shelley Vohr)
[#&#8203;57910](https://redirect.github.com/nodejs/node/pull/57910)
-
\[[`03936f31c1`](https://redirect.github.com/nodejs/node/commit/03936f31c1)]
- **src**: fixup errorhandling more in various places (James M Snell)
[#&#8203;57852](https://redirect.github.com/nodejs/node/pull/57852)
-
\[[`010dd91a19`](https://redirect.github.com/nodejs/node/commit/010dd91a19)]
- **src**: fix typo in comments (Edy Silva)
[#&#8203;57868](https://redirect.github.com/nodejs/node/pull/57868)
-
\[[`e00c1ecbd2`](https://redirect.github.com/nodejs/node/commit/e00c1ecbd2)]
- **src**: add BaseObjectPtr nullptr operations (Chengzhong Wu)
[#&#8203;56585](https://redirect.github.com/nodejs/node/pull/56585)
-
\[[`648ad252e1`](https://redirect.github.com/nodejs/node/commit/648ad252e1)]
- **src**: remove `void*` -> `char*` -> `void*` casts (Tobias Nießen)
[#&#8203;57791](https://redirect.github.com/nodejs/node/pull/57791)
-
\[[`680b434a62`](https://redirect.github.com/nodejs/node/commit/680b434a62)]
- **src**: improve error handing in node_messaging (James M Snell)
[#&#8203;57760](https://redirect.github.com/nodejs/node/pull/57760)
-
\[[`18f5301747`](https://redirect.github.com/nodejs/node/commit/18f5301747)]
- **src**: remove unused detachArrayBuffer method (Yagiz Nizipli)
[#&#8203;58055](https://redirect.github.com/nodejs/node/pull/58055)
-
\[[`065e8cd670`](https://redirect.github.com/nodejs/node/commit/065e8cd670)]
- **src**: use macros to reduce code duplication is cares_wrap (James M
Snell)
[#&#8203;57937](https://redirect.github.com/nodejs/node/pull/57937)
-
\[[`39af5d678f`](https://redirect.github.com/nodejs/node/commit/39af5d678f)]
- **src**: improve error handling in cares_wrap (James M Snell)
[#&#8203;57937](https://redirect.github.com/nodejs/node/pull/57937)
-
\[[`ca020fdc4e`](https://redirect.github.com/nodejs/node/commit/ca020fdc4e)]
- **src**: fix -Wunreachable-code-return in node_sea (Shelley Vohr)
[#&#8203;57664](https://redirect.github.com/nodejs/node/pull/57664)
-
\[[`32b6e7094a`](https://redirect.github.com/nodejs/node/commit/32b6e7094a)]
- **src**: change DCHECK to CHECK (Wuli Zuo)
[#&#8203;57948](https://redirect.github.com/nodejs/node/pull/57948)
-
\[[`e1d3a9e192`](https://redirect.github.com/nodejs/node/commit/e1d3a9e192)]
- **(SEMVER-MINOR)** **src**: add ExecutionAsyncId getter for any
Context (Attila Szegedi)
[#&#8203;57820](https://redirect.github.com/nodejs/node/pull/57820)
-
\[[`96243a723a`](https://redirect.github.com/nodejs/node/commit/96243a723a)]
- **src**: update std::vector\<v8::Local\<T>> to use v8::LocalVector\<T>
(Aditi)
[#&#8203;57646](https://redirect.github.com/nodejs/node/pull/57646)
-
\[[`0f2cbc17c7`](https://redirect.github.com/nodejs/node/commit/0f2cbc17c7)]
- **src**: update std::vector\<v8::Local\<T>> to use v8::LocalVector\<T>
(Aditi)
[#&#8203;57642](https://redirect.github.com/nodejs/node/pull/57642)
-
\[[`d1c6f861d5`](https://redirect.github.com/nodejs/node/commit/d1c6f861d5)]
- **src**: update std::vector\<v8::Local\<T>> to use v8::LocalVector\<T>
(Aditi)
[#&#8203;57578](https://redirect.github.com/nodejs/node/pull/57578)
-
\[[`ab0d3a38db`](https://redirect.github.com/nodejs/node/commit/ab0d3a38db)]
- **src**: improve error message for invalid child stdio type in
spawn_sync (Dario Piotrowicz)
[#&#8203;57589](https://redirect.github.com/nodejs/node/pull/57589)
-
\[[`24b182e7b3`](https://redirect.github.com/nodejs/node/commit/24b182e7b3)]
- **src**: implement util.types fast API calls (Ruben Bridgewater)
[#&#8203;57819](https://redirect.github.com/nodejs/node/pull/57819)
-
\[[`dda6423be9`](https://redirect.github.com/nodejs/node/commit/dda6423be9)]
- **src**: enter and lock isolate properly in json parser (Joyee Cheung)
[#&#8203;57823](https://redirect.github.com/nodejs/node/pull/57823)
-
\[[`4754c693f8`](https://redirect.github.com/nodejs/node/commit/4754c693f8)]
- **src**: improve error handling in `node_env_var.cc` (Antoine du
Hamel)
[#&#8203;57767](https://redirect.github.com/nodejs/node/pull/57767)
-
\[[`db483bbe63`](https://redirect.github.com/nodejs/node/commit/db483bbe63)]
- **src**: improve error handling in node_http2 (James M Snell)
[#&#8203;57764](https://redirect.github.com/nodejs/node/pull/57764)
-
\[[`b0277700d6`](https://redirect.github.com/nodejs/node/commit/b0277700d6)]
- **src**: improve error handling in crypto_x509 (James M Snell)
[#&#8203;57757](https://redirect.github.com/nodejs/node/pull/57757)
-
\[[`353587f984`](https://redirect.github.com/nodejs/node/commit/353587f984)]
- **src**: improve error handling in callback.cc (James M Snell)
[#&#8203;57758](https://redirect.github.com/nodejs/node/pull/57758)
-
\[[`bec053ab20`](https://redirect.github.com/nodejs/node/commit/bec053ab20)]
- **src**: remove unused variable in crypto_x509.cc (Michaël Zasso)
[#&#8203;57754](https://redirect.github.com/nodejs/node/pull/57754)
-
\[[`38a329a857`](https://redirect.github.com/nodejs/node/commit/38a329a857)]
- **src**: fix kill signal 0 on Windows (Stefan Stojanovic)
[#&#8203;57695](https://redirect.github.com/nodejs/node/pull/57695)
-
\[[`70bb387f82`](https://redirect.github.com/nodejs/node/commit/70bb387f82)]
- **src**: fix inefficient usage of v8\_inspector::StringView (Simon
Zünd)
[#&#8203;52372](https://redirect.github.com/nodejs/node/pull/52372)
-
\[[`be038f0273`](https://redirect.github.com/nodejs/node/commit/be038f0273)]
- **src,permission**: make ERR_ACCESS_DENIED more descriptive (Rafael
Gonzaga)
[#&#8203;57585](https://redirect.github.com/nodejs/node/pull/57585)
-
\[[`0ec912f452`](https://redirect.github.com/nodejs/node/commit/0ec912f452)]
- **(SEMVER-MINOR)** **stream**: preserve AsyncLocalStorage context in
finished() (Gürgün Dayıoğlu)
[#&#8203;57865](https://redirect.github.com/nodejs/node/pull/57865)
-
\[[`6ffb66f82f`](https://redirect.github.com/nodejs/node/commit/6ffb66f82f)]
- **test**: fix permission fixtures lint (Rafael Gonzaga)
[#&#8203;55819](https://redirect.github.com/nodejs/node/pull/55819)
-
\[[`fd37891186`](https://redirect.github.com/nodejs/node/commit/fd37891186)]
- **test**: add repl preview timeout test (Chengzhong Wu)
[#&#8203;55484](https://redirect.github.com/nodejs/node/pull/55484)
-
\[[`1be5a8c1b4`](https://redirect.github.com/nodejs/node/commit/1be5a8c1b4)]
- **test**: skip `test-config-json-schema` with quic (Richard Lau)
[#&#8203;57225](https://redirect.github.com/nodejs/node/pull/57225)
-
\[[`e90583b657`](https://redirect.github.com/nodejs/node/commit/e90583b657)]
- **test**: add more coverage to `node_config_file` (Marco Ippolito)
[#&#8203;57170](https://redirect.github.com/nodejs/node/pull/57170)
-
\[[`df2a36bfcc`](https://redirect.github.com/nodejs/node/commit/df2a36bfcc)]
- **test**: remove deadlock workaround (Joyee Cheung)
[#&#8203;58047](https://redirect.github.com/nodejs/node/pull/58047)
-
\[[`103034b051`](https://redirect.github.com/nodejs/node/commit/103034b051)]
- **test**: prevent extraneous HOSTNAME substitution in
test-runner-output (René)
[#&#8203;58076](https://redirect.github.com/nodejs/node/pull/58076)
-
\[[`3e58f81a38`](https://redirect.github.com/nodejs/node/commit/3e58f81a38)]
- **test**: update WPT for WebCryptoAPI to
[`b48efd6`](https://redirect.github.com/nodejs/node/commit/b48efd681e)
(Node.js GitHub Bot)
[#&#8203;58044](https://redirect.github.com/nodejs/node/pull/58044)
-
\[[`2f4e4164a3`](https://redirect.github.com/nodejs/node/commit/2f4e4164a3)]
- **test**: add missing newlines to repl .exit writes (Dario Piotrowicz)
[#&#8203;58041](https://redirect.github.com/nodejs/node/pull/58041)
-
\[[`b40769292e`](https://redirect.github.com/nodejs/node/commit/b40769292e)]
- **test**: add fast api tests for getLibuvNow() (Yagiz Nizipli)
[#&#8203;58022](https://redirect.github.com/nodejs/node/pull/58022)
-
\[[`cbd5768d47`](https://redirect.github.com/nodejs/node/commit/cbd5768d47)]
- **test**: add ALS test using http agent keep alive (Gerhard Stöbich)
[#&#8203;58017](https://redirect.github.com/nodejs/node/pull/58017)
-
\[[`9e31ab502a`](https://redirect.github.com/nodejs/node/commit/9e31ab502a)]
- **test**: deflake test-http2-options-max-headers-block-length (Luigi
Pinca)
[#&#8203;57959](https://redirect.github.com/nodejs/node/pull/57959)
-
\[[`13f8f9cc12`](https://redirect.github.com/nodejs/node/commit/13f8f9cc12)]
- **test**: rename to getCallSites (Wuli Zuo)
[#&#8203;57948](https://redirect.github.com/nodejs/node/pull/57948)
-
\[[`92dce6ed6b`](https://redirect.github.com/nodejs/node/commit/92dce6ed6b)]
- **test**: force GC in test-file-write-stream4 (Luigi Pinca)
[#&#8203;57930](https://redirect.github.com/nodejs/node/pull/57930)
-
\[[`aa755d3acf`](https://redirect.github.com/nodejs/node/commit/aa755d3acf)]
- **test**: enable skipped colorize test (Shima Ryuhei)
[#&#8203;57887](https://redirect.github.com/nodejs/node/pull/57887)
-
\[[`331f44c78c`](https://redirect.github.com/nodejs/node/commit/331f44c78c)]
- **test**: update WPT for WebCryptoAPI to
[`164426a`](https://redirect.github.com/nodejs/node/commit/164426ace2)
(Node.js GitHub Bot)
[#&#8203;57854](https://redirect.github.com/nodejs/node/pull/57854)
-
\[[`4aaa8438b4`](https://redirect.github.com/nodejs/node/commit/4aaa8438b4)]
- **test**: add test for frame count being 0.5 (Jake Yuesong Li)
[#&#8203;57732](https://redirect.github.com/nodejs/node/pull/57732)
-
\[[`fb51d3a0c5`](https://redirect.github.com/nodejs/node/commit/fb51d3a0c5)]
- **test**: fix the decimal fractions explaination (Jake Yuesong Li)
[#&#8203;57732](https://redirect.github.com/nodejs/node/pull/57732)
-
\[[`c6a45a9087`](https://redirect.github.com/nodejs/node/commit/c6a45a9087)]
- ***Revert*** "**test**: add tests for REPL custom evals" (Tobias
Nießen)
[#&#8203;57793](https://redirect.github.com/nodejs/node/pull/57793)
-
\[[`f3a4d03963`](https://redirect.github.com/nodejs/node/commit/f3a4d03963)]
- **test**: add tests for REPL custom evals (Dario Piotrowicz)
[#&#8203;57691](https://redirect.github.com/nodejs/node/pull/57691)
-
\[[`a3be0df337`](https://redirect.github.com/nodejs/node/commit/a3be0df337)]
- **test**: update expected error message for macOS (Antoine du Hamel)
[#&#8203;57742](https://redirect.github.com/nodejs/node/pull/57742)
-
\[[`a7e73a0a74`](https://redirect.github.com/nodejs/node/commit/a7e73a0a74)]
- **test**: fix dangling promise in test_runner no isolation test setup
(Jacob Smith)
[#&#8203;57595](https://redirect.github.com/nodejs/node/pull/57595)
-
\[[`edb7dd1ec7`](https://redirect.github.com/nodejs/node/commit/edb7dd1ec7)]
- **test_runner**: match minimum file column to 'all files' (Shima
Ryuhei)
[#&#8203;57848](https://redirect.github.com/nodejs/node/pull/57848)
-
\[[`c56f495e83`](https://redirect.github.com/nodejs/node/commit/c56f495e83)]
- **tools**: extract target abseil to abseil.gyp (Chengzhong Wu)
[#&#8203;57289](https://redirect.github.com/nodejs/node/pull/57289)
-
\[[`1b37161a27`](https://redirect.github.com/nodejs/node/commit/1b37161a27)]
- **tools**: ignore V8 tests in CodeQL scans (Rich Trott)
[#&#8203;58081](https://redirect.github.com/nodejs/node/pull/58081)
-
\[[`23386308dd`](https://redirect.github.com/nodejs/node/commit/23386308dd)]
- **tools**: enable CodeQL config file (Rich Trott)
[#&#8203;58036](https://redirect.github.com/nodejs/node/pull/58036)
-
\[[`9c21abc169`](https://redirect.github.com/nodejs/node/commit/9c21abc169)]
- **tools**: ignore test directory in CodeQL scans (Rich Trott)
[#&#8203;57978](https://redirect.github.com/nodejs/node/pull/57978)
-
\[[`f210a1530d`](https://redirect.github.com/nodejs/node/commit/f210a1530d)]
- **tools**: add semver-major release support to release-lint (Antoine
du Hamel)
[#&#8203;57892](https://redirect.github.com/nodejs/node/pull/57892)
-
\[[`234c417e98`](https://redirect.github.com/nodejs/node/commit/234c417e98)]
- **tools**: add codeql nightly (Rafael Gonzaga)
[#&#8203;57788](https://redirect.github.com/nodejs/node/pull/57788)
-
\[[`938f1532da`](https://redirect.github.com/nodejs/node/commit/938f1532da)]
- **tools**: edit create-release-proposal workflow to handle pr body
length (Elves Vieira)
[#&#8203;57841](https://redirect.github.com/nodejs/node/pull/57841)
-
\[[`b362339f72`](https://redirect.github.com/nodejs/node/commit/b362339f72)]
- **tools**: add zstd updater to workflow (KASEYA\yahor.siarheyenka)
[#&#8203;57831](https://redirect.github.com/nodejs/node/pull/57831)
-
\[[`61180db9c0`](https://redirect.github.com/nodejs/node/commit/61180db9c0)]
- **tools**: remove unused `osx-pkg-postinstall.sh` (Antoine du Hamel)
[#&#8203;57667](https://redirect.github.com/nodejs/node/pull/57667)
-
\[[`3ae04c94eb`](https://redirect.github.com/nodejs/node/commit/3ae04c94eb)]
- **tools**: do not use temp files when merging PRs (Antoine du Hamel)
[#&#8203;57790](https://redirect.github.com/nodejs/node/pull/57790)
-
\[[`d623c2c2b4`](https://redirect.github.com/nodejs/node/commit/d623c2c2b4)]
- **tools

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC4xNi4wIiwidXBkYXRlZEluVmVyIjoiNDAuNjAuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-20 17:13:54 -04:00
renovate[bot]
53ca41404f fix(deps): update dependency vue-sonner to v2 (#1401)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [vue-sonner](https://redirect.github.com/xiaoluoboding/vue-sonner) |
[`^1.3.0` ->
`^2.0.0`](https://renovatebot.com/diffs/npm/vue-sonner/1.3.0/2.0.0) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/vue-sonner/2.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/vue-sonner/2.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/vue-sonner/1.3.0/2.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/vue-sonner/1.3.0/2.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>xiaoluoboding/vue-sonner (vue-sonner)</summary>

###
[`v2.0.0`](https://redirect.github.com/xiaoluoboding/vue-sonner/blob/HEAD/CHANGELOG.md#200-2025-05-21)

[Compare
Source](https://redirect.github.com/xiaoluoboding/vue-sonner/compare/v1.3.2...v2.0.0)

##### Bug Fixes

- add packages path
([35490b3](35490b3fb5))
- add packages path
([c7424e9](c7424e9070))
- fixed for nuxt module
([261eaf0](261eaf0be2))
- fixed for nuxt module
([29751cf](29751cfd5b))
- format
([9033f2b](9033f2b935))

####
[1.3.2](https://redirect.github.com/xiaoluoboding/vue-sonner/compare/v1.3.0...v1.3.2)
(2025-04-12)

##### Bug Fixes

- improve CSS insertion logic to handle document loading state
([6b22d24](6b22d2458b))

###
[`v1.3.2`](https://redirect.github.com/xiaoluoboding/vue-sonner/blob/HEAD/CHANGELOG.md#132-2025-04-12)

[Compare
Source](c1208885b3...v1.3.2)

##### Bug Fixes

- improve CSS insertion logic to handle document loading state
([6b22d24](6b22d2458b))

###
[`v1.3.1`](https://redirect.github.com/xiaoluoboding/vue-sonner/compare/v1.3.0...c1208885b35167216568e305e8a1cb1bc786f128)

[Compare
Source](https://redirect.github.com/xiaoluoboding/vue-sonner/compare/v1.3.0...c1208885b35167216568e305e8a1cb1bc786f128)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC4xNi4wIiwidXBkYXRlZEluVmVyIjoiNDAuMTYuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-20 17:06:14 -04:00
renovate[bot]
9492c2ae6a fix(deps): update dependency cache-manager to v7 (#1413)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [cache-manager](https://redirect.github.com/jaredwray/cacheable)
([source](https://redirect.github.com/jaredwray/cacheable/tree/HEAD/packages/cache-manager))
| [`^6.4.2` ->
`^7.0.0`](https://renovatebot.com/diffs/npm/cache-manager/6.4.2/7.0.0) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/cache-manager/7.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/cache-manager/7.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/cache-manager/6.4.2/7.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/cache-manager/6.4.2/7.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC40MC4zIiwidXBkYXRlZEluVmVyIjoiNDAuNDAuMyIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-20 17:05:55 -04:00
renovate[bot]
3eb92dc9ea chore(deps): update dependency happy-dom to v18 (#1414)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [happy-dom](https://redirect.github.com/capricorn86/happy-dom) |
[`^17.4.4` ->
`^18.0.0`](https://renovatebot.com/diffs/npm/happy-dom/17.4.4/18.0.1) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/happy-dom/18.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/happy-dom/18.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/happy-dom/17.4.4/18.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/happy-dom/17.4.4/18.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [happy-dom](https://redirect.github.com/capricorn86/happy-dom) |
[`^17.0.0` ->
`^18.0.0`](https://renovatebot.com/diffs/npm/happy-dom/17.4.4/18.0.1) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/happy-dom/18.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/happy-dom/18.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/happy-dom/17.4.4/18.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/happy-dom/17.4.4/18.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>capricorn86/happy-dom (happy-dom)</summary>

###
[`v18.0.1`](https://redirect.github.com/capricorn86/happy-dom/compare/v18.0.0...cf74f5f63ca562e075c9c14b77ecfbb8fbc43dea)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v18.0.0...v18.0.1)

###
[`v18.0.0`](https://redirect.github.com/capricorn86/happy-dom/compare/v17.6.3...bfd0fffc12f23c6f31174953f65c4f57925e7212)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.6.3...v18.0.0)

###
[`v17.6.3`](https://redirect.github.com/capricorn86/happy-dom/releases/tag/v17.6.3)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.6.2...v17.6.3)

##### 👷‍♂️ Patch fixes

- Removes global typescript definition that was used for custom elements
- By **[@&#8203;capricorn86](https://redirect.github.com/capricorn86)**
in task
[#&#8203;1154](https://redirect.github.com/capricorn86/happy-dom/issues/1154)

###
[`v17.6.2`](https://redirect.github.com/capricorn86/happy-dom/releases/tag/v17.6.2)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.6.1...v17.6.2)

##### 👷‍♂️ Patch fixes

- Updates Typescript to the latest version - By
**[@&#8203;capricorn86](https://redirect.github.com/capricorn86)** in
task
[#&#8203;1154](https://redirect.github.com/capricorn86/happy-dom/issues/1154)

###
[`v17.6.1`](https://redirect.github.com/capricorn86/happy-dom/releases/tag/v17.6.1)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.6.0...v17.6.1)

##### 🎨 Features

- Adds support for disabling validation of certificates, to allow for
self-signed certificates to be used - By
**[@&#8203;capricorn86](https://redirect.github.com/capricorn86)** in
task
[#&#8203;1763](https://redirect.github.com/capricorn86/happy-dom/issues/1763)
- Read more about the new setting `fetch.disableStrictSSL` under
[IBrowserSettings](https://redirect.github.com/capricorn86/happy-dom/wiki/IBrowserSettings)
in the Wiki

###
[`v17.6.0`](https://redirect.github.com/capricorn86/happy-dom/compare/v17.5.9...v17.6.0)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.5.9...v17.6.0)

###
[`v17.5.9`](https://redirect.github.com/capricorn86/happy-dom/releases/tag/v17.5.9)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.5.8...v17.5.9)

##### 👷‍♂️ Patch fixes

- Adds missing null check in `HTMLLinkElement` for a browser frame
property that becomes null during teardown of a `Window` - By
**[@&#8203;capricorn86](https://redirect.github.com/capricorn86)** in
task
[#&#8203;1800](https://redirect.github.com/capricorn86/happy-dom/issues/1800)

###
[`v17.5.8`](https://redirect.github.com/capricorn86/happy-dom/releases/tag/v17.5.8)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.5.7...v17.5.8)

##### 👷‍♂️ Patch fixes

- Incorrect cache matching caused `Element.classList` to return the
wrong items - By
**[@&#8203;capricorn86](https://redirect.github.com/capricorn86)** in
task
[#&#8203;1812](https://redirect.github.com/capricorn86/happy-dom/issues/1812)

###
[`v17.5.7`](https://redirect.github.com/capricorn86/happy-dom/releases/tag/v17.5.7)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.5.6...v17.5.7)

##### 👷‍♂️ Patch fixes

- Handle wider range of valid characters in unquoted attribute value
parsing - By **[@&#8203;AudunWA](https://redirect.github.com/AudunWA)**
in task
[#&#8203;1817](https://redirect.github.com/capricorn86/happy-dom/issues/1817)

###
[`v17.5.6`](https://redirect.github.com/capricorn86/happy-dom/releases/tag/v17.5.6)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.5.5...v17.5.6)

##### 👷‍♂️ Patch fixes

- Removes the min and max boundary check when setting the value of an
input field of type "date" - By
**[@&#8203;zgrybus](https://redirect.github.com/zgrybus)** in task
[#&#8203;1815](https://redirect.github.com/capricorn86/happy-dom/issues/1815)

###
[`v17.5.5`](https://redirect.github.com/capricorn86/happy-dom/compare/v17.5.4...v17.5.5)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.5.4...v17.5.5)

###
[`v17.5.4`](https://redirect.github.com/capricorn86/happy-dom/releases/tag/v17.5.4)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.5.3...v17.5.4)

##### 👷‍♂️ Patch fixes

- Fixes issue where the body of a `ReadableStream` was locked after
being cloned - By
**[@&#8203;MarcMcIntosh](https://redirect.github.com/MarcMcIntosh)** in
task
[#&#8203;1493](https://redirect.github.com/capricorn86/happy-dom/issues/1493)

###
[`v17.5.3`](https://redirect.github.com/capricorn86/happy-dom/releases/tag/v17.5.3)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.5.2...v17.5.3)

##### 👷‍♂️ Patch fixes

- Adds `previousSibling` and `nextSibling` to `MutationObserver` records
when a child is removed - By
**[@&#8203;uxuip](https://redirect.github.com/uxuip)** in task
[#&#8203;1803](https://redirect.github.com/capricorn86/happy-dom/issues/1803)

###
[`v17.5.2`](https://redirect.github.com/capricorn86/happy-dom/compare/v17.5.1...b257aa136e3cdf74046f0a2dd8d07b4d44b50436)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.5.1...v17.5.2)

###
[`v17.5.1`](https://redirect.github.com/capricorn86/happy-dom/releases/tag/v17.5.1)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.5.0...v17.5.1)

##### 👷‍♂️ Patch fixes

- Existing URL query string should be overwritten on form submit when
method is "GET" - By
**[@&#8203;rslabbert](https://redirect.github.com/rslabbert)** in task
[#&#8203;1786](https://redirect.github.com/capricorn86/happy-dom/issues/1786)

###
[`v17.5.0`](https://redirect.github.com/capricorn86/happy-dom/releases/tag/v17.5.0)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.4.9...v17.5.0)

##### 🎨 Features

- Adds support for `XMLHttpRequest.overrideMimeType()` - By
**[@&#8203;maxmil](https://redirect.github.com/maxmil)** in task
[#&#8203;1782](https://redirect.github.com/capricorn86/happy-dom/issues/1782)

###
[`v17.4.9`](https://redirect.github.com/capricorn86/happy-dom/compare/v17.4.8...4ec75b75d53a9f436afc737e24f9ff07a4e6ec87)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.4.8...v17.4.9)

###
[`v17.4.8`](https://redirect.github.com/capricorn86/happy-dom/releases/tag/v17.4.8)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.4.7...v17.4.8)

##### 👷‍♂️ Patch fixes

- Fixes issue where CSS variables where not being parsed in color
functions - By
**[@&#8203;hampustagerud](https://redirect.github.com/hampustagerud)**
in task
[#&#8203;1822](https://redirect.github.com/capricorn86/happy-dom/issues/1822)

###
[`v17.4.7`](https://redirect.github.com/capricorn86/happy-dom/releases/tag/v17.4.7)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.4.6...v17.4.7)

##### 👷‍♂️ Patch fixes

- Allow empty URL string in `Request` - By
**[@&#8203;elierotenberg](https://redirect.github.com/elierotenberg)**
in task
[#&#8203;1779](https://redirect.github.com/capricorn86/happy-dom/issues/1779)

###
[`v17.4.6`](https://redirect.github.com/capricorn86/happy-dom/releases/tag/v17.4.6)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.4.5...v17.4.6)

##### 👷‍♂️ Patch fixes

- Preserve slashes in the "name" property in `File` - By
**[@&#8203;dyabol](https://redirect.github.com/dyabol)** in task
[#&#8203;1788](https://redirect.github.com/capricorn86/happy-dom/issues/1788)

###
[`v17.4.5`](https://redirect.github.com/capricorn86/happy-dom/releases/tag/v17.4.5)

[Compare
Source](https://redirect.github.com/capricorn86/happy-dom/compare/v17.4.4...v17.4.5)

##### 👷‍♂️ Patch fixes

- Handle bubbling click events in `HTMLAnchorElement` - By
**[@&#8203;maxmil](https://redirect.github.com/maxmil)** in task
[#&#8203;1775](https://redirect.github.com/capricorn86/happy-dom/issues/1775)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these
updates again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC40OC41IiwidXBkYXRlZEluVmVyIjoiNDAuNDguNSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-20 17:05:37 -04:00
Eli Bosley
f12d231e63 fix: debounce is too long (#1426)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Refactor**
- Reduced the delay before configuration changes are processed,
resulting in faster response times to configuration updates throughout
the application.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-20 11:07:53 -04:00
Eli Bosley
75ad8381bd fix: theme issues when sent from graph (#1424)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Bug Fixes**
- Improved error handling and fallback logic when loading themes,
ensuring default values are used if loading fails or data is missing.
- **Refactor**
- Updated theme customization options to improve type accuracy and allow
certain color fields to be optional.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-20 09:50:45 -04:00
Eli Bosley
9901039a38 feat: docker and info resolver issues (#1423)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Bug Fixes**
- The system info query now returns only the `id` field, with other
details loaded separately.
- **Chores**
- Internal service dependencies were updated for improved
maintainability.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-19 11:50:02 -04:00
Pujit Mehrotra
70c790ff89 fix: alignment of settings on ManagementAccess settings page (#1421)
## Summary by CodeRabbit

- **Refactor**
- Removed description text display from a form field for a cleaner
interface.
- Enhanced form field matching to better target specific string array
inputs.
- Updated remote access settings UI for clearer layout and separation of
title and details.
  - Adjusted label container styling to allow more flexible width.
- Improved grouping of precondition information for better visual
structure.
  - Added a colon to the SSO users settings label for consistency.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210572375587668
2025-06-19 08:46:18 -04:00
Eli Bosley
0788756b91 feat: add management page for API keys (#1408)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added ability to update existing API keys, including name,
description, roles, and permissions, through the UI and GraphQL API.
- Introduced a modal-based interface for creating and editing API keys
with improved role and permission selection.
- Added a new API Key Manager page and custom element for centralized
API key management.
- Enhanced API key listing with detailed views, role badges, permission
counters, and copy-to-clipboard functionality.
- Introduced reusable dialog components for consistent modal
experiences.
- Added plugin management capabilities with mutations to add or remove
plugins.
- Added comprehensive support for managing remote access, network URLs,
and API key updates within the GraphQL schema.

- **Bug Fixes**
- Improved error handling and display for API key creation and update
operations.

- **Refactor**
- Centralized API key modal and editing state management using a
dedicated store.
- Updated GraphQL queries and mutations to use reusable fragments for
API key data.
- Removed deprecated or redundant remote access and allowed origins
configuration components and queries.
- Simplified and updated input types for connect settings and remote
access.

- **Tests**
- Added comprehensive tests for API key update logic and improved
coverage for API key loading.

- **Chores**
- Updated configuration files and cleaned up unused schema and component
files.
  - Added new dialog components and centralized exports for dialogs.
- Improved ESLint configuration and import statements for better type
handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-18 11:18:36 -04:00
Pujit Mehrotra
d9ab58eb83 chore: require connect plugin to enable flash backup (#1419)
## Summary by CodeRabbit

- **New Features**
- Added a check to ensure the "unraid-api-plugin-connect" plugin is
enabled before allowing flash backup functionality.
- Introduced a utility to directly verify if specific API plugins are
enabled.

- **Refactor**
- Updated internal logic to use a centralized class and script-based
checks for plugin status and version instead of manual config parsing.
- Improved script command-line interface for easier plugin status and
version checks.

- **Bug Fixes**
- Flash Backup feature and service now only activate when the required
API plugin is enabled, preventing unintended usage.
- Flash Backup UI is conditionally displayed based on the presence of
the API plugin.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1209357561531351
  - https://app.asana.com/0/0/1210541992642236
2025-06-18 10:20:59 -04:00
Pujit Mehrotra
642a220c3a feat: add graphql resource for API plugins (#1420)
Addresses #1350 

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Introduced a plugin management system, allowing users to view, add,
and remove plugins through the API.
- Added the ability to control plugin installation options, including
bundled installation and API restart behavior.

- **Removals**
- Removed all remote access, network, and cloud-related features and
settings from the API.

- **Improvements**
- Enhanced API queries and mutations to focus on plugin management and
metadata.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-16 14:18:13 -04:00
Michael Datelle
b6c4ee6eb4 feat: initialize claude code in codebse (#1418)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Documentation**
- Added a comprehensive onboarding and contribution guide covering
project structure, development commands, architecture, workflows, and
coding/testing standards.
- **Chores**
  - Introduced a local settings file for configuration management.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: mdatelle <mike@datelle.net>
2025-06-16 13:28:40 -04:00
Pujit Mehrotra
8c8a5276b4 fix: omit Connect actions in UPC when plugin is not installed (#1417)
Removes Connect branding in dropdown when connect plugin is not installed.

Preview of dropdown:
<img width="453" alt="image"
src="https://github.com/user-attachments/assets/b3ba3954-f2d3-4760-a1e2-91556eb43903"
/>

## Summary by CodeRabbit

- **New Features**
- The Notifications Sidebar is now always visible in the user profile,
regardless of plugin installation status.

- **Refactor**
  - Improved detection logic for the connect plugin to enhance accuracy.
- Centralized and standardized the "Settings" link in the user profile
dropdown for consistent user experience.
- The account status section in Connect Settings now only appears when
the connect plugin is installed.
- Updated the Connect page title from "Unraid Connect" to "Unraid API"
for clarity.

- **Chores**
- Extended linting to include Vue files for better code quality
enforcement.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-16 11:50:37 -04:00
Pujit Mehrotra
3dcbfbe489 feat: api plugin management via CLI (#1416)
implements unraid-api `plugins list`, `plugins install`, `plugins remove` commands via a new `DependencyService` that invokes npm.

## Summary by CodeRabbit

- **New Features**
- Enhanced plugin management with install, remove, and list commands
supporting bundled plugins and restart control.
- Added plugin persistence and configuration synchronization across API
settings and interfaces.
- Introduced dependency management service for streamlined npm
operations and vendor archive rebuilding.
- **Bug Fixes**
- Improved plugin listing accuracy with warnings for configured but
missing plugins.
- **Chores**
- Refactored CLI modules and services for unified plugin management and
dependency handling.
- Updated API configuration loading and persistence for better
separation of concerns.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-12 09:37:36 -04:00
Pujit Mehrotra
184b76de1c chore: include node_modules in api slackware package (#1415)
instead of vendoring & uploading separately.

## Summary by CodeRabbit

- **Chores**
- Updated build process to retain the `node_modules` directory, removing
compression and archiving steps.
- Improved plugin installation by cleaning up outdated dependency
archives before reinstalling, enhancing system stability.
- Removed vendor store file references and related bundling steps from
the plugin build and installation process.
- Enhanced dependency restoration during service start to log warnings
without aborting on failure.
- Simplified dependency management scripts by removing vendor store URL
handling and download functionality.
- Streamlined build workflows by removing artifact upload/download and
validation steps related to node modules archives.
- Updated Docker Compose configuration to remove unused volume mounts
for node modules archives.
- Added repository cleanup commands to remove top-level `node_modules`
directories and common build artifact folders for easier maintenance.
2025-06-11 12:07:32 -04:00
Pujit Mehrotra
c132f28281 chore: extract connect to an API plugin (#1367)
separates Unraid Connect from the API

## Summary by CodeRabbit

- **New Features**
- Introduced a unified, JSON-schema-based settings system for API
configuration and plugin settings, accessible via new GraphQL queries
and mutations.
- Added modular NestJS plugin architecture for Unraid Connect, including
new modules for cloud, remote access, and system/network management.
- Added granular connection and remote access state tracking, with new
GraphQL types and resolvers for cloud and connection status.
- Implemented event-driven and service-based management for SSO users,
API keys, and dynamic remote access.
- Enhanced UI components and queries to support unified settings and
restart detection.

- **Improvements**
- Refactored configuration and state management to use service-based
patterns, replacing direct store access and Redux logic.
- Migrated legacy config files to new JSON formats with validation and
persistence helpers.
- Centralized global dependencies and shared services for plugins and
CLI modules.
- Improved logging, error handling, and lifecycle management for
connections and background jobs.
- Updated and expanded documentation for plugin development and settings
management.

- **Bug Fixes**
- Improved handling of missing config files and ensured safe
persistence.
- Enhanced error reporting and validation in remote access and
connection services.

- **Removals**
- Removed deprecated Redux slices, listeners, and legacy cloud/remote
access logic.
- Deleted obsolete test files, scripts, and unused code related to the
old state/store approach.

- **Tests**
- Added new unit tests for settings merging, URL resolution, and cloud
connectivity checks.

- **Style**
- Applied consistent formatting, import reorganization, and code style
improvements across modules.

- **Chores**
- Updated build scripts, Dockerfiles, and development environment setup
to support new dependencies and workflows.
- Expanded .gitignore and configuration files for improved build
artifact management.
2025-06-10 15:16:26 -04:00
Eli Bosley
5517e7506b feat: add rclone (#1362)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Introduced full RClone remote management with creation, deletion,
listing, and detailed remote info via a multi-step, schema-driven UI.
- Added guided configuration forms supporting advanced and
provider-specific options for RClone remotes.
  - Enabled flash backup initiation through API mutations.
- Added new Vue components for RClone configuration, overview, remote
item cards, and flash backup page.
- Integrated new combobox, stepped layout, control wrapper, label
renderer, and improved form renderers with enhanced validation and error
display.
- Added JSON Forms visibility composable and Unraid settings layout for
consistent UI rendering.

- **Bug Fixes**
- Standardized JSON scalar usage in Docker-related types, replacing
`JSONObject` with `JSON`.

- **Chores**
- Added utility scripts and helpers to manage rclone binary installation
and versioning.
- Updated build scripts and Storybook configuration for CSS handling and
improved developer workflow.
- Refactored ESLint config for modularity and enhanced code quality
enforcement.
- Improved component registration with runtime type checks and error
handling.

- **Documentation**
- Added extensive test coverage for RClone API service, JSON Forms
schema merging, and provider config slice generation.

- **Style**
- Improved UI consistency with new layouts, tooltips on select options,
password visibility toggles, and error handling components.
- Removed deprecated components and consolidated renderer registrations
for JSON Forms.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-05-27 07:52:25 -04:00
Eli Bosley
d37dc3bce2 feat: API key management (#1407)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added a full-featured API key management UI, including creation,
listing, and deletion of API keys with customizable roles and
permissions.
  - Introduced a new page for API key management.
- Accordion UI components are now available for enhanced interface
interactions.
  - API now provides queries for possible API key roles and permissions.

- **Improvements**
- API key-related mutations are now grouped under a single field,
improving organization and usability.
  - Permissions can be assigned directly to API keys, not just roles.

- **Bug Fixes**
- Validation updated to require at least one role or permission when
creating an API key.

- **Documentation**
- Updated and added rules and configuration documentation for code
generation and testing.

- **Tests**
- Added and updated tests for new API key mutation logic; removed
obsolete tests for deprecated mutations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-05-23 13:12:26 -04:00
Eli Bosley
83076bb940 fix: rc.unraid-api now cleans up older dependencies (#1404)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added an option to clean up old dependency files, keeping only those
needed for the current API version.
- Introduced a direct cleanup command to remove outdated dependencies
before installing new ones.

- **Bug Fixes**
- Improved handling and messaging for missing or invalid dependency
information during cleanup operations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-05-23 10:23:58 -04:00
Eli Bosley
7b005cbbf6 fix: node_modules dir removed on plugin update (#1406)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Chores**
- Improved installation process by automatically cleaning up old package
directories before installing or upgrading the package.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-05-23 09:22:59 -04:00
Eli Bosley
b625227913 fix: move to bigint scalar 2025-05-22 15:01:12 -04:00
Eli Bosley
e54d27aede fix: bigint 2025-05-22 14:59:37 -04:00
Eli Bosley
574d572d65 feat: use bigint instead of long (#1403)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Improved support for large integer values in the API, allowing
accurate handling of big numbers in GraphQL queries and responses.
- **Bug Fixes**
- Enhanced reliability when dealing with very large numeric fields,
reducing the risk of data loss or inaccuracies for disk, share, and
memory statistics.
- **Chores**
	- Updated internal dependencies to improve handling of big integers.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-05-22 13:42:36 -04:00
Eli Bosley
5355115af2 fix: simplify usb listing (#1402)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Refactor**
- Improved USB device detection for increased reliability and
performance.
- Device names are now displayed based on basic device information, with
unnamed devices labeled appropriately.
	- GUID generation for devices is simplified and more robust.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210189043307638
2025-05-22 13:42:26 -04:00
Eli Bosley
881f1e0960 feat: slightly better watch mode (#1398)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Added a script to automatically prepare UI components before running
the build watch process in the web app.
- **Bug Fixes**
- Improved build and release processes to ensure directories are
properly cleaned and created, preventing potential errors during Docker
operations.
- **Chores**
- Updated build watch scripts for faster development feedback and more
efficient parallel execution.
- Refined Docker Compose configuration to use the correct release
directory for plugin builds.
- Introduced a new script to streamline and centralize file watching and
build triggering in the plugin system.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-05-22 13:42:08 -04:00
Eli Bosley
7067e9e3dd fix: proper fallback if missing paths config modules 2025-05-22 09:40:36 -04:00
Eli Bosley
f71943b62b feat: send active unraid theme to docs (#1400)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- The changelog modal now automatically syncs its theme (dark or light
mode) with the rest of the application.
- Added a new test button to preview the changelog from a localhost URL.
- **Improvements**
- Enhanced navigation handling within the embedded changelog, ensuring
only allowed links are followed.
- Improved communication between the modal and its embedded content for
a more seamless user experience.
- Updated the app layout to better support light and dark themes with
consistent background and text colors.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-05-21 16:35:30 -04:00
Eli Bosley
9ce2fee380 fix: use some instead of every for connect detection 2025-05-21 10:32:21 -04:00
Eli Bosley
7d88b3393c fix: do not start API with doinst.sh 2025-05-20 17:42:49 -04:00
Michael Datelle
f6ec2839b5 test: create tests for components batch 5 (#1397)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Tests**
- Added a new test suite for the Avatar component to verify its
conditional rendering based on user and plugin state.
- Enhanced existing tests with additional mocks to improve test
isolation and reliability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: mdatelle <mike@datelle.net>
2025-05-20 15:46:34 -04:00
Eli Bosley
02de89d130 fix: disable file changes on Unraid 7.2 (#1382)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Improved login security by supporting Single Sign-On (SSO) in the
login flow.
- Centralized and enhanced theme management for a more consistent
appearance across pages.

- **Refactor**
- Simplified and modularized page layouts and theme handling using
helper classes.
- Moved inline scripts and styles to external files for better
maintainability.
- Replaced legacy notification system with a modern toaster UI
component.
  - Streamlined session handling for localhost requests.
- Updated version checks to conditionally skip modifications for Unraid
7.2 compatibility.
- Replaced direct version imports with dynamic imports for better load
management.

- **Bug Fixes**
- Conditional logic added to prevent applying certain modifications on
Unraid 7.2.0 and above for improved compatibility.

- **Chores**
- Introduced a unified Vitest workspace configuration for streamlined
testing across multiple projects.
  - Added comprehensive tests for Unraid version comparison logic.
- Adjusted logging levels for activation-related messages to reduce
noise in logs.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-05-20 15:14:55 -04:00
Michael Datelle
eb080e5d22 test: create tests for components batch 4 (#1384)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Tests**
- Added comprehensive unit tests for the activation code data store,
covering loading states, activation code retrieval, fresh install
detection, and partner info resolution under various scenarios.
- Introduced new tests for the activation code modal store, validating
state management, visibility logic, and Konami code sequence handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: mdatelle <mike@datelle.net>
2025-05-20 10:15:06 -04:00
Eli Bosley
edc0d1578b fix: always download 7.1 versioned files for patching 2025-05-20 09:05:56 -04:00
Eli Bosley
fcd6fbcdd4 feat: move to iframe for changelog (#1388)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Changelog modal now displays changelog documentation within an
embedded iframe if a URL is available, allowing navigation within the
iframe and providing a "Back to Changelog" button to return to the
original view.
- "View on Docs" button dynamically updates to reflect the current page
within the iframe.
- Added support for displaying a formatted changelog string and testing
modal behavior with or without this content.
- Introduced a new component to fetch, parse, and render changelogs from
URLs with enhanced markdown handling.
- Update OS store extended to manage changelog display and release
stability, consolidating changelog state and actions.

- **Bug Fixes**
  - Close button in modal dialogs is now visible on all screen sizes.

- **Chores**
- Updated the default server state, which may affect registration device
counts and types.
- Added new localization string for changelog titles with version
placeholders.
- Removed deprecated changelog store and related tests, simplifying
state management.
- Refined backup and restoration scripts for unraid-components directory
to use move operations with improved logging.
- Improved modal visibility state handling by consolidating changelog
modal controls into the main update OS store.
- Added URL origin and pattern checks for changelog iframe navigation
security.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-05-19 15:34:44 -04:00
renovate[bot]
fc68ea03d1 chore(deps): update dependency shadcn-nuxt to v2 (#1301)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [shadcn-nuxt](https://redirect.github.com/unovue/shadcn-vue)
([source](https://redirect.github.com/unovue/shadcn-vue/tree/HEAD/packages/module))
| [`^1.0.0` ->
`^2.0.0`](https://renovatebot.com/diffs/npm/shadcn-nuxt/1.0.3/2.0.0) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/shadcn-nuxt/2.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/shadcn-nuxt/2.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/shadcn-nuxt/1.0.3/2.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/shadcn-nuxt/1.0.3/2.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>unovue/shadcn-vue (shadcn-nuxt)</summary>

###
[`v2.0.0`](https://redirect.github.com/unovue/shadcn-vue/releases/tag/v2.0.0)

[Compare
Source](https://redirect.github.com/unovue/shadcn-vue/compare/v1.0.3...v2.0.0)

#####    🚀 Features

- Tailwind v4  -  by
[@&#8203;zernonia](https://redirect.github.com/zernonia) in
[https://github.com/unovue/shadcn-vue/issues/1095](https://redirect.github.com/unovue/shadcn-vue/issues/1095)
[<samp>(c18e1)</samp>](https://redirect.github.com/unovue/shadcn-vue/commit/c18e129f)
- **docs**: Add a plugin to generate documentation for LLMs  -  by
[@&#8203;okineadev](https://redirect.github.com/okineadev) in
[https://github.com/unovue/shadcn-vue/issues/1119](https://redirect.github.com/unovue/shadcn-vue/issues/1119)
[<samp>(0d72c)</samp>](https://redirect.github.com/unovue/shadcn-vue/commit/0d72cef5)

#####    🐞 Bug Fixes

- Tailwind extra space on prefix when having " " in class  -  by
[@&#8203;AloisH](https://redirect.github.com/AloisH) in
[https://github.com/unovue/shadcn-vue/issues/1098](https://redirect.github.com/unovue/shadcn-vue/issues/1098)
[<samp>(69fee)</samp>](https://redirect.github.com/unovue/shadcn-vue/commit/69fee21d)
- Extra space on class causing error in applying prefix  -  by
[@&#8203;AloisH](https://redirect.github.com/AloisH) in
[https://github.com/unovue/shadcn-vue/issues/1109](https://redirect.github.com/unovue/shadcn-vue/issues/1109)
[<samp>(51655)</samp>](https://redirect.github.com/unovue/shadcn-vue/commit/51655218)
- Codesandbox not found pnpm  -  by
[@&#8203;hairyf](https://redirect.github.com/hairyf) in
[https://github.com/unovue/shadcn-vue/issues/1127](https://redirect.github.com/unovue/shadcn-vue/issues/1127)
[<samp>(9c12e)</samp>](https://redirect.github.com/unovue/shadcn-vue/commit/9c12ebb2)
- Styling of chart legend reset every click  -  by
[@&#8203;AloisH](https://redirect.github.com/AloisH) in
[https://github.com/unovue/shadcn-vue/issues/1125](https://redirect.github.com/unovue/shadcn-vue/issues/1125)
[<samp>(46e6f)</samp>](https://redirect.github.com/unovue/shadcn-vue/commit/46e6f7a4)

#####     [View changes on
GitHub](https://redirect.github.com/unovue/shadcn-vue/compare/v1.0.3...v2.0.0)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4yMDcuMSIsInVwZGF0ZWRJblZlciI6IjM5LjIwNy4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-19 12:19:13 -04:00
renovate[bot]
26ecf779e6 fix(deps): update dependency shadcn-vue to v2 (#1302)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [shadcn-vue](https://redirect.github.com/unovue/shadcn-vue)
([source](https://redirect.github.com/unovue/shadcn-vue/tree/HEAD/packages/cli))
| [`^1.0.0` ->
`^2.0.0`](https://renovatebot.com/diffs/npm/shadcn-vue/1.0.3/2.0.0) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/shadcn-vue/2.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/shadcn-vue/2.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/shadcn-vue/1.0.3/2.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/shadcn-vue/1.0.3/2.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>unovue/shadcn-vue (shadcn-vue)</summary>

###
[`v2.0.0`](https://redirect.github.com/unovue/shadcn-vue/releases/tag/v2.0.0)

[Compare
Source](https://redirect.github.com/unovue/shadcn-vue/compare/v1.0.3...v2.0.0)

#####    🚀 Features

- Tailwind v4  -  by
[@&#8203;zernonia](https://redirect.github.com/zernonia) in
[https://github.com/unovue/shadcn-vue/issues/1095](https://redirect.github.com/unovue/shadcn-vue/issues/1095)
[<samp>(c18e1)</samp>](https://redirect.github.com/unovue/shadcn-vue/commit/c18e129f)
- **docs**: Add a plugin to generate documentation for LLMs  -  by
[@&#8203;okineadev](https://redirect.github.com/okineadev) in
[https://github.com/unovue/shadcn-vue/issues/1119](https://redirect.github.com/unovue/shadcn-vue/issues/1119)
[<samp>(0d72c)</samp>](https://redirect.github.com/unovue/shadcn-vue/commit/0d72cef5)

#####    🐞 Bug Fixes

- Tailwind extra space on prefix when having " " in class  -  by
[@&#8203;AloisH](https://redirect.github.com/AloisH) in
[https://github.com/unovue/shadcn-vue/issues/1098](https://redirect.github.com/unovue/shadcn-vue/issues/1098)
[<samp>(69fee)</samp>](https://redirect.github.com/unovue/shadcn-vue/commit/69fee21d)
- Extra space on class causing error in applying prefix  -  by
[@&#8203;AloisH](https://redirect.github.com/AloisH) in
[https://github.com/unovue/shadcn-vue/issues/1109](https://redirect.github.com/unovue/shadcn-vue/issues/1109)
[<samp>(51655)</samp>](https://redirect.github.com/unovue/shadcn-vue/commit/51655218)
- Codesandbox not found pnpm  -  by
[@&#8203;hairyf](https://redirect.github.com/hairyf) in
[https://github.com/unovue/shadcn-vue/issues/1127](https://redirect.github.com/unovue/shadcn-vue/issues/1127)
[<samp>(9c12e)</samp>](https://redirect.github.com/unovue/shadcn-vue/commit/9c12ebb2)
- Styling of chart legend reset every click  -  by
[@&#8203;AloisH](https://redirect.github.com/AloisH) in
[https://github.com/unovue/shadcn-vue/issues/1125](https://redirect.github.com/unovue/shadcn-vue/issues/1125)
[<samp>(46e6f)</samp>](https://redirect.github.com/unovue/shadcn-vue/commit/46e6f7a4)

#####     [View changes on
GitHub](https://redirect.github.com/unovue/shadcn-vue/compare/v1.0.3...v2.0.0)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4yMDcuMSIsInVwZGF0ZWRJblZlciI6IjM5LjIwNy4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-19 12:19:04 -04:00
renovate[bot]
00da27d04f fix(deps): update dependency @types/diff to v8 (#1393)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
|
[@types/diff](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/diff)
([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/diff))
| [`^7.0.1` ->
`^8.0.0`](https://renovatebot.com/diffs/npm/@types%2fdiff/7.0.2/8.0.0) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/@types%2fdiff/8.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@types%2fdiff/8.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@types%2fdiff/7.0.2/8.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@types%2fdiff/7.0.2/8.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC4xMS4xOCIsInVwZGF0ZWRJblZlciI6IjQwLjExLjE4IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-19 12:18:39 -04:00
renovate[bot]
106ea09399 fix(deps): update dependency commander to v14 (#1394)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [commander](https://redirect.github.com/tj/commander.js) | [`^13.1.0`
-> `^14.0.0`](https://renovatebot.com/diffs/npm/commander/13.1.0/14.0.0)
|
[![age](https://developer.mend.io/api/mc/badges/age/npm/commander/14.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/commander/14.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/commander/13.1.0/14.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/commander/13.1.0/14.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>tj/commander.js (commander)</summary>

###
[`v14.0.0`](https://redirect.github.com/tj/commander.js/blob/HEAD/CHANGELOG.md#1400-2025-05-18)

[Compare
Source](https://redirect.github.com/tj/commander.js/compare/v13.1.0...v14.0.0)

##### Added

- support for groups of options and commands in the help using low-level
`.helpGroup()` on `Option` and `Command`, and higher-level
`.optionsGroup()` and `.commandsGroup()` which can be used in chaining
way to specify group title for following options/commands
(\[[#&#8203;2328](https://redirect.github.com/tj/commander.js/issues/2328)])
- support for unescaped negative numbers as option-arguments and
command-arguments
(\[[#&#8203;2339](https://redirect.github.com/tj/commander.js/issues/2339)])
- TypeScript: add `parseArg` property to `Argument` class
(\[[#&#8203;2359](https://redirect.github.com/tj/commander.js/issues/2359)])

##### Fixed

- remove bogus leading space in help when option has default value but
not a description
(\[[#&#8203;2348](https://redirect.github.com/tj/commander.js/issues/2348)])
- `.configureOutput()` now makes copy of settings instead of modifying
in-place, fixing side-effects
(\[[#&#8203;2350](https://redirect.github.com/tj/commander.js/issues/2350)])

##### Changed

-   *Breaking:* Commander 14 requires Node.js v20 or higher
- internal refactor of `Help` class adding `.formatItemList()` and
`.groupItems()` methods
(\[[#&#8203;2328](https://redirect.github.com/tj/commander.js/issues/2328)])

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC4xMS4xOCIsInVwZGF0ZWRJblZlciI6IjQwLjExLjE4IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-19 12:17:59 -04:00
renovate[bot]
cb43f95233 fix(deps): update all non-major dependencies (#1389)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence | Type |
Update |
|---|---|---|---|---|---|---|---|
| [lucide-vue-next](https://lucide.dev)
([source](https://redirect.github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-vue-next))
| [`^0.510.0` ->
`^0.511.0`](https://renovatebot.com/diffs/npm/lucide-vue-next/0.510.0/0.511.0)
|
[![age](https://developer.mend.io/api/mc/badges/age/npm/lucide-vue-next/0.511.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/lucide-vue-next/0.511.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/lucide-vue-next/0.510.0/0.511.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/lucide-vue-next/0.510.0/0.511.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
| dependencies | minor |
| [node](https://nodejs.org)
([source](https://redirect.github.com/nodejs/node)) | `22.15.0` ->
`22.15.1` |
[![age](https://developer.mend.io/api/mc/badges/age/node-version/node/v22.15.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/node-version/node/v22.15.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/node-version/node/v22.15.0/v22.15.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/node-version/node/v22.15.0/v22.15.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
| | patch |

---

### Release Notes

<details>
<summary>lucide-icons/lucide (lucide-vue-next)</summary>

###
[`v0.511.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.511.0):
Version 0.511.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.510.0...0.511.0)

#### What's Changed

- fix(icons): Optimise a number of icons using `<line>` and `<polyline>`
by [@&#8203;jamiemlaw](https://redirect.github.com/jamiemlaw) in
[https://github.com/lucide-icons/lucide/pull/3168](https://redirect.github.com/lucide-icons/lucide/pull/3168)
- fix(icons): changed `clock-6` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3209](https://redirect.github.com/lucide-icons/lucide/pull/3209)
- fix(icons): changed `axis-3d` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3199](https://redirect.github.com/lucide-icons/lucide/pull/3199)
- fix(icons): changed `chevrons-left-right-ellipsis` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3189](https://redirect.github.com/lucide-icons/lucide/pull/3189)
- fix(icons): changed `square-code` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3173](https://redirect.github.com/lucide-icons/lucide/pull/3173)
- fix(icons): changed `satellite` icon by
[@&#8203;karsa-mistmere](https://redirect.github.com/karsa-mistmere) in
[https://github.com/lucide-icons/lucide/pull/3180](https://redirect.github.com/lucide-icons/lucide/pull/3180)
- fix(lucide-react-native): support react 19
([#&#8203;2951](https://redirect.github.com/lucide-icons/lucide/issues/2951))
by [@&#8203;jvliwanag](https://redirect.github.com/jvliwanag) in
[https://github.com/lucide-icons/lucide/pull/3126](https://redirect.github.com/lucide-icons/lucide/pull/3126)
- fix(icons): changed `factory` icon by
[@&#8203;karsa-mistmere](https://redirect.github.com/karsa-mistmere) in
[https://github.com/lucide-icons/lucide/pull/2970](https://redirect.github.com/lucide-icons/lucide/pull/2970)
- fix(icons): changed `university` icon by
[@&#8203;karsa-mistmere](https://redirect.github.com/karsa-mistmere) in
[https://github.com/lucide-icons/lucide/pull/2965](https://redirect.github.com/lucide-icons/lucide/pull/2965)
- fix(icons): changed `warehouse` icon by
[@&#8203;karsa-mistmere](https://redirect.github.com/karsa-mistmere) in
[https://github.com/lucide-icons/lucide/pull/2966](https://redirect.github.com/lucide-icons/lucide/pull/2966)
- fix(icons): changed `landmark` icon by
[@&#8203;karsa-mistmere](https://redirect.github.com/karsa-mistmere) in
[https://github.com/lucide-icons/lucide/pull/2967](https://redirect.github.com/lucide-icons/lucide/pull/2967)
- chore(cspell): remove duplicate 'pilcrow' from `custom-words.txt` by
[@&#8203;Abdalrhman-Almarakeby](https://redirect.github.com/Abdalrhman-Almarakeby)
in
[https://github.com/lucide-icons/lucide/pull/3193](https://redirect.github.com/lucide-icons/lucide/pull/3193)
- feat(icons): added `square-dashed-top-solid` icon by
[@&#8203;juanpablofernandez](https://redirect.github.com/juanpablofernandez)
in
[https://github.com/lucide-icons/lucide/pull/3204](https://redirect.github.com/lucide-icons/lucide/pull/3204)

#### New Contributors

- [@&#8203;jvliwanag](https://redirect.github.com/jvliwanag) made their
first contribution in
[https://github.com/lucide-icons/lucide/pull/3126](https://redirect.github.com/lucide-icons/lucide/pull/3126)
-
[@&#8203;juanpablofernandez](https://redirect.github.com/juanpablofernandez)
made their first contribution in
[https://github.com/lucide-icons/lucide/pull/3204](https://redirect.github.com/lucide-icons/lucide/pull/3204)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.510.0...0.511.0

</details>

<details>
<summary>nodejs/node (node)</summary>

###
[`v22.15.1`](https://redirect.github.com/nodejs/node/compare/v22.15.0...v22.15.1)

[Compare
Source](https://redirect.github.com/nodejs/node/compare/v22.15.0...v22.15.1)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC4xMS45IiwidXBkYXRlZEluVmVyIjoiNDAuMTEuMTgiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-19 12:17:39 -04:00
renovate[bot]
d26c6b0760 chore(deps): update github/codeql-action action to v3 (#1391)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[github/codeql-action](https://redirect.github.com/github/codeql-action)
| action | major | `v2` -> `v3` |

---

### Release Notes

<details>
<summary>github/codeql-action (github/codeql-action)</summary>

###
[`v3`](https://redirect.github.com/github/codeql-action/compare/v2...v3)

[Compare
Source](https://redirect.github.com/github/codeql-action/compare/v2...v3)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC4xMS45IiwidXBkYXRlZEluVmVyIjoiNDAuMTEuOSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-19 12:17:31 -04:00
Eli Bosley
2ade7eb527 feat: initial codeql setup (#1390) 2025-05-14 20:21:52 -04:00
renovate[bot]
e580f646a5 fix(deps): update dependency diff to v8 (#1386)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [diff](https://redirect.github.com/kpdecker/jsdiff) | [`^7.0.0` ->
`^8.0.0`](https://renovatebot.com/diffs/npm/diff/7.0.0/8.0.0) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/diff/8.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/diff/8.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/diff/7.0.0/8.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/diff/7.0.0/8.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>kpdecker/jsdiff (diff)</summary>

###
[`v8.0.0`](https://redirect.github.com/kpdecker/jsdiff/blob/HEAD/release-notes.md#800)

[Compare
Source](https://redirect.github.com/kpdecker/jsdiff/compare/7.0.0...v8.0.0)

- [#&#8203;580](https://redirect.github.com/kpdecker/jsdiff/pull/580)
**Multiple tweaks to `diffSentences`**:
- tokenization no longer takes quadratic time on pathological inputs
(reported as a ReDOS vulnerability by Snyk); is now linear instead
- the final sentence in the string is now handled the same by the
tokenizer regardless of whether it has a trailing punctuation mark or
not. (Previously, "foo. bar." tokenized to `["foo.", " ", "bar."]` but
"foo. bar" tokenized to `["foo.", " bar"]` - i.e. whether the space
between sentences was treated as a separate token depended upon whether
the final sentence had trailing punctuation or not. This was arbitrary
and surprising; it is no longer the case.)
- in a string that starts with a sentence end, like "! hello.", the "!"
is now treated as a separate sentence
- the README now correctly documents the tokenization behaviour (it was
wrong before)
- [#&#8203;581](https://redirect.github.com/kpdecker/jsdiff/pull/581) -
**fixed some regex operations used for tokenization in `diffWords`
taking O(n^2) time** in pathological cases
- [#&#8203;595](https://redirect.github.com/kpdecker/jsdiff/pull/595) -
**fixed a crash in patch creation functions when handling a single hunk
consisting of a very large number (e.g. >130k) of lines**. (This was
caused by spreading indefinitely-large arrays to `.push()` using
`.apply` or the spread operator and hitting the
JS-implementation-specific limit on the maximum number of arguments to a
function, as shown at https://stackoverflow.com/a/56809779/1709587; thus
the exact threshold to hit the error will depend on the environment in
which you were running JsDiff.)
- [#&#8203;596](https://redirect.github.com/kpdecker/jsdiff/pull/596) -
**removed the `merge` function**. Previously JsDiff included an
undocumented function called `merge` that was meant to, in some sense,
merge patches. It had at least a couple of serious bugs that could lead
to it returning unambiguously wrong results, and it was difficult to
simply "fix" because it was [unclear precisely what it was meant to
do](https://redirect.github.com/kpdecker/jsdiff/issues/181#issuecomment-2198319542).
For now, the fix is to remove it entirely.
- [#&#8203;591](https://redirect.github.com/kpdecker/jsdiff/pull/591) -
JsDiff's source code has been rewritten in TypeScript. This change
entails the following changes for end users:
- **the `diff` package on npm now includes its own TypeScript type
definitions**. Users who previously used the `@types/diff` npm package
from DefinitelyTyped should remove that dependency when upgrading JsDiff
to v8.

Note that the transition from the DefinitelyTyped types to JsDiff's own
type definitions includes multiple fixes and also removes many exported
types previously used for `options` arguments to diffing and
patch-generation functions. (There are now different exported options
types for abortable calls - ones with a `timeout` or `maxEditLength`
that may give a result of `undefined` - and non-abortable calls.) See
the TypeScript section of the README for some usage tips.

- **The `Diff` object is now a class**. Custom extensions of `Diff`, as
described in the "Defining custom diffing behaviors" section of the
README, can therefore now be done by writing a `class CustomDiff extends
Diff` and overriding methods, instead of the old way based on prototype
inheritance. (I *think* code that did things the old way should still
work, though!)

- **`diff/lib/index.es6.js` and `diff/lib/index.mjs` no longer exist,
and the ESM version of the library is no longer bundled into a single
file.**

- **The `ignoreWhitespace` option for `diffWords` is no longer included
in the type declarations**. The effect of passing `ignoreWhitespace:
true` has always been to make `diffWords` just call `diffWordsWithSpace`
instead, which was confusing, because that behaviour doesn't seem
properly described as "ignoring" whitespace at all. The property remains
available to non-TypeScript applications for the sake of backwards
compatability, but TypeScript applications will now see a type error if
they try to pass `ignoreWhitespace: true` to `diffWords` and should
change their code to call `diffWordsWithSpace` instead.

- JsDiff no longer purports to support ES3 environments. (I'm pretty
sure it never truly did, despite claiming to in its README, since even
the 1.0.0 release used `Array.map` which was added in ES5.)
- [#&#8203;601](https://redirect.github.com/kpdecker/jsdiff/pull/601) -
**`diffJson`'s `stringifyReplacer` option behaves more like
`JSON.stringify`'s `replacer` argument now.** In particular:
- Each key/value pair now gets passed through the replacer once instead
of twice
- The `key` passed to the replacer when the top-level object is passed
in as `value` is now `""` (previously, was `undefined`), and the `key`
passed with an array element is the array index as a string, like `"0"`
or `"1"` (previously was whatever the key for the entire array was).
Both the new behaviours match that of `JSON.stringify`.
- [#&#8203;602](https://redirect.github.com/kpdecker/jsdiff/pull/602) -
**diffing functions now consistently return `undefined` when called in
async mode** (i.e. with a callback). Previously, there was an odd quirk
where they would return `true` if the strings being diffed were equal
and `undefined` otherwise.

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC43LjEiLCJ1cGRhdGVkSW5WZXIiOiI0MC43LjEiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-14 11:52:08 -04:00
renovate[bot]
2704c0464c chore(deps): update dependency lint-staged to v16 (#1385)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [lint-staged](https://redirect.github.com/lint-staged/lint-staged) |
[`^15.2.2` ->
`^16.0.0`](https://renovatebot.com/diffs/npm/lint-staged/15.5.1/16.0.0)
|
[![age](https://developer.mend.io/api/mc/badges/age/npm/lint-staged/16.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/lint-staged/16.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/lint-staged/15.5.1/16.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/lint-staged/15.5.1/16.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>lint-staged/lint-staged (lint-staged)</summary>

###
[`v16.0.0`](https://redirect.github.com/lint-staged/lint-staged/blob/HEAD/CHANGELOG.md#1600)

[Compare
Source](https://redirect.github.com/lint-staged/lint-staged/compare/v15.5.2...v16.0.0)

##### Major Changes

-
[#&#8203;1546](https://redirect.github.com/lint-staged/lint-staged/pull/1546)
[`158d15c`](158d15c9ae)
Thanks [@&#8203;iiroj](https://redirect.github.com/iiroj)! - Processes
are spawned using
[nano-spawn](https://redirect.github.com/sindresorhus/nano-spawn)
instead of [execa](https://redirect.github.com/sindresorhus/execa). If
you are using Node.js scripts as tasks, you might need to explicitly run
them with `node`, especially when using Windows:

    ```json
    {
      "*.js": "node my-js-linter.js"
    }
    ```

-
[#&#8203;1546](https://redirect.github.com/lint-staged/lint-staged/pull/1546)
[`158d15c`](158d15c9ae)
Thanks [@&#8203;iiroj](https://redirect.github.com/iiroj)! - The
`--shell` flag has been removed and *lint-staged* no longer supports
evaluating commands directly via a shell. To migrate existing commands,
you can create a shell script and invoke it instead. Lint-staged will
pass matched staged files as a list of arguments, accessible via
`"$@&#8203;"`:

    ```shell
    ```

###
[`v15.5.2`](https://redirect.github.com/lint-staged/lint-staged/blob/HEAD/CHANGELOG.md#1552)

[Compare
Source](https://redirect.github.com/lint-staged/lint-staged/compare/v15.5.1...v15.5.2)

##### Patch Changes

-
[#&#8203;1544](https://redirect.github.com/lint-staged/lint-staged/pull/1544)
[`5561321`](556132176a)
Thanks [@&#8203;YimingIsCOLD](https://redirect.github.com/YimingIsCOLD)!
- Correctly handle colon (`:`) characters in staged filenames.

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC43LjEiLCJ1cGRhdGVkSW5WZXIiOiI0MC43LjEiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-14 11:51:55 -04:00
renovate[bot]
74a70b5557 fix(deps): update all non-major dependencies (#1387)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [lucide-vue-next](https://lucide.dev)
([source](https://redirect.github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-vue-next))
| [`^0.509.0` ->
`^0.510.0`](https://renovatebot.com/diffs/npm/lucide-vue-next/0.509.0/0.510.0)
|
[![age](https://developer.mend.io/api/mc/badges/age/npm/lucide-vue-next/0.510.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/lucide-vue-next/0.510.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/lucide-vue-next/0.509.0/0.510.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/lucide-vue-next/0.509.0/0.510.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [pnpm](https://pnpm.io)
([source](https://redirect.github.com/pnpm/pnpm/tree/HEAD/pnpm)) |
[`10.10.0` ->
`10.11.0`](https://renovatebot.com/diffs/npm/pnpm/10.10.0/10.11.0) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/pnpm/10.11.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/pnpm/10.11.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/pnpm/10.10.0/10.11.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/pnpm/10.10.0/10.11.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>lucide-icons/lucide (lucide-vue-next)</summary>

###
[`v0.510.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.510.0):
Version 0.510.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.509.0...0.510.0)

#### What's Changed

- fix(icons): changed `brackets` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3172](https://redirect.github.com/lucide-icons/lucide/pull/3172)
- feat(icons): added `check-line` icon by
[@&#8203;oosawy](https://redirect.github.com/oosawy) in
[https://github.com/lucide-icons/lucide/pull/2890](https://redirect.github.com/lucide-icons/lucide/pull/2890)

#### New Contributors

- [@&#8203;oosawy](https://redirect.github.com/oosawy) made their first
contribution in
[https://github.com/lucide-icons/lucide/pull/2890](https://redirect.github.com/lucide-icons/lucide/pull/2890)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.509.0...0.510.0

</details>

<details>
<summary>pnpm/pnpm (pnpm)</summary>

###
[`v10.11.0`](https://redirect.github.com/pnpm/pnpm/blob/HEAD/pnpm/CHANGELOG.md#10110)

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v10.10.0...v10.11.0)

##### Minor Changes

- A new setting added for `pnpm init` to create a `package.json` with
`type=module`, when `init-type` is `module`. Works as a flag for the
init command too
[#&#8203;9463](https://redirect.github.com/pnpm/pnpm/pull/9463).

- Added support for Nushell to `pnpm setup`
[#&#8203;6476](https://redirect.github.com/pnpm/pnpm/issues/6476).

- Added two new flags to the `pnpm audit` command, `--ignore` and
`--ignore-unfixable`
[#&#8203;8474](https://redirect.github.com/pnpm/pnpm/pull/8474).

    Ignore all vulnerabilities that have no solution:

    ```shell
    > pnpm audit --ignore-unfixable
    ```

Provide a list of CVE's to ignore those specifically, even if they have
a resolution.

    ```shell
    > pnpm audit --ignore=CVE-2021-1234 --ignore=CVE-2021-5678
    ```

- Added support for recursively running pack in every project of a
workspace
[#&#8203;4351](https://redirect.github.com/pnpm/pnpm/issues/4351).

Now you can run `pnpm -r pack` to pack all packages in the workspace.

##### Patch Changes

- pnpm version management should work, when `dangerouslyAllowAllBuilds`
is set to `true`
[#&#8203;9472](https://redirect.github.com/pnpm/pnpm/issues/9472).
- `pnpm link` should work from inside a workspace
[#&#8203;9506](https://redirect.github.com/pnpm/pnpm/issues/9506).
- Set the default `workspaceConcurrency` to
`Math.min(os.availableParallelism(), 4)`
[#&#8203;9493](https://redirect.github.com/pnpm/pnpm/pull/9493).
- Installation should not exit with an error if `strictPeerDependencies`
is `true` but all issues are ignored by `peerDependencyRules`
[#&#8203;9505](https://redirect.github.com/pnpm/pnpm/pull/9505).
- Read `updateConfig` from `pnpm-workspace.yaml`
[#&#8203;9500](https://redirect.github.com/pnpm/pnpm/issues/9500).
-   Add support for `recursive pack`
- Remove `url.parse` usage to fix warning on Node.js 24
[#&#8203;9492](https://redirect.github.com/pnpm/pnpm/issues/9492).
- `pnpm run` should be able to run commands from the workspace root, if
`ignoreScripts` is set tot `true`
[#&#8203;4858](https://redirect.github.com/pnpm/pnpm/issues/4858).

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC43LjEiLCJ1cGRhdGVkSW5WZXIiOiI0MC4xMS45IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-14 11:51:42 -04:00
renovate[bot]
469333acd4 fix(deps): update dependency lucide-vue-next to ^0.509.0 (#1383)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [lucide-vue-next](https://lucide.dev)
([source](https://redirect.github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-vue-next))
| [`^0.508.0` ->
`^0.509.0`](https://renovatebot.com/diffs/npm/lucide-vue-next/0.508.0/0.509.0)
|
[![age](https://developer.mend.io/api/mc/badges/age/npm/lucide-vue-next/0.509.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/lucide-vue-next/0.509.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/lucide-vue-next/0.508.0/0.509.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/lucide-vue-next/0.508.0/0.509.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>lucide-icons/lucide (lucide-vue-next)</summary>

###
[`v0.509.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.509.0):
Version 0.509.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.508.0...0.509.0)

#### What's Changed

- fix(icons): changed `axe` icon by
[@&#8203;karsa-mistmere](https://redirect.github.com/karsa-mistmere) in
[https://github.com/lucide-icons/lucide/pull/3201](https://redirect.github.com/lucide-icons/lucide/pull/3201)
- revert(site): resets Absolute Stroke Width by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3197](https://redirect.github.com/lucide-icons/lucide/pull/3197)
- feat(icons): added `gpu` icon by
[@&#8203;xandykati98](https://redirect.github.com/xandykati98) in
[https://github.com/lucide-icons/lucide/pull/2955](https://redirect.github.com/lucide-icons/lucide/pull/2955)

#### New Contributors

- [@&#8203;xandykati98](https://redirect.github.com/xandykati98) made
their first contribution in
[https://github.com/lucide-icons/lucide/pull/2955](https://redirect.github.com/lucide-icons/lucide/pull/2955)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.508.0...0.509.0

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC43LjEiLCJ1cGRhdGVkSW5WZXIiOiI0MC43LjEiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-09 08:24:39 -04:00
renovate[bot]
8f70326d0f fix(deps): update all non-major dependencies (#1379)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence | Type |
Update |
|---|---|---|---|---|---|---|---|
|
[@graphql-codegen/typescript-resolvers](https://redirect.github.com/dotansimha/graphql-code-generator)
([source](https://redirect.github.com/dotansimha/graphql-code-generator/tree/HEAD/packages/plugins/typescript/resolvers))
| [`4.5.0` ->
`4.5.1`](https://renovatebot.com/diffs/npm/@graphql-codegen%2ftypescript-resolvers/4.5.0/4.5.1)
|
[![age](https://developer.mend.io/api/mc/badges/age/npm/@graphql-codegen%2ftypescript-resolvers/4.5.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@graphql-codegen%2ftypescript-resolvers/4.5.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@graphql-codegen%2ftypescript-resolvers/4.5.0/4.5.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@graphql-codegen%2ftypescript-resolvers/4.5.0/4.5.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
| devDependencies | patch |
| [lucide-vue-next](https://lucide.dev)
([source](https://redirect.github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-vue-next))
| [`^0.506.0` ->
`^0.508.0`](https://renovatebot.com/diffs/npm/lucide-vue-next/0.506.0/0.508.0)
|
[![age](https://developer.mend.io/api/mc/badges/age/npm/lucide-vue-next/0.508.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/lucide-vue-next/0.508.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/lucide-vue-next/0.506.0/0.508.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/lucide-vue-next/0.506.0/0.508.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
| dependencies | minor |
| [node](https://nodejs.org)
([source](https://redirect.github.com/nodejs/node)) | `22.11.0` ->
`22.15.0` |
[![age](https://developer.mend.io/api/mc/badges/age/node-version/node/v22.15.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/node-version/node/v22.15.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/node-version/node/v22.11.0/v22.15.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/node-version/node/v22.11.0/v22.15.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
| | minor |

---

### Release Notes

<details>
<summary>dotansimha/graphql-code-generator
(@&#8203;graphql-codegen/typescript-resolvers)</summary>

###
[`v4.5.1`](https://redirect.github.com/dotansimha/graphql-code-generator/blob/HEAD/packages/plugins/typescript/resolvers/CHANGELOG.md#451)

[Compare
Source](https://redirect.github.com/dotansimha/graphql-code-generator/compare/@graphql-codegen/typescript-resolvers@4.5.0...@graphql-codegen/typescript-resolvers@4.5.1)

##### Patch Changes

-
[#&#8203;10330](https://redirect.github.com/dotansimha/graphql-code-generator/pull/10330)
[`c5efba3`](c5efba34a7)
Thanks [@&#8203;jnoordsij](https://redirect.github.com/jnoordsij)! -
Make graphql-sock optional peerDep

</details>

<details>
<summary>lucide-icons/lucide (lucide-vue-next)</summary>

###
[`v0.508.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.508.0):
Version 0.508.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.507.0...0.508.0)

#### What's Changed

- fix(icons): Optimised `phone-` icons by
[@&#8203;jamiemlaw](https://redirect.github.com/jamiemlaw) in
[https://github.com/lucide-icons/lucide/pull/3169](https://redirect.github.com/lucide-icons/lucide/pull/3169)
- docs(packages): Update names in docs by
[@&#8203;ericfennis](https://redirect.github.com/ericfennis) in
[https://github.com/lucide-icons/lucide/pull/3184](https://redirect.github.com/lucide-icons/lucide/pull/3184)
- fix(icons): arcified `laptop` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3190](https://redirect.github.com/lucide-icons/lucide/pull/3190)
- chore(metadata): add `lens` tag to icons with magnifying glass by
[@&#8203;Abdalrhman-Almarakeby](https://redirect.github.com/Abdalrhman-Almarakeby)
in
[https://github.com/lucide-icons/lucide/pull/3192](https://redirect.github.com/lucide-icons/lucide/pull/3192)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.507.0...0.508.0

###
[`v0.507.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.507.0):
Version 0.507.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.506.0...0.507.0)

#### What's Changed

- fix(metadata): added tags to `square-pen` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3155](https://redirect.github.com/lucide-icons/lucide/pull/3155)
- fix(icons): changed `search` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3140](https://redirect.github.com/lucide-icons/lucide/pull/3140)
- fix(dev): resets Absolute Stroke Width by
[@&#8203;briz123](https://redirect.github.com/briz123) in
[https://github.com/lucide-icons/lucide/pull/3005](https://redirect.github.com/lucide-icons/lucide/pull/3005)
- fix(icons): changed `guitar` icon by
[@&#8203;jamiemlaw](https://redirect.github.com/jamiemlaw) in
[https://github.com/lucide-icons/lucide/pull/3115](https://redirect.github.com/lucide-icons/lucide/pull/3115)
- fix(Icons): Adding missing categories to 4 Icons by
[@&#8203;ajokt123](https://redirect.github.com/ajokt123) in
[https://github.com/lucide-icons/lucide/pull/3110](https://redirect.github.com/lucide-icons/lucide/pull/3110)
- fix(ci): reduces workflow triggers by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3150](https://redirect.github.com/lucide-icons/lucide/pull/3150)
- fix(icons): changed `air-vent` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3117](https://redirect.github.com/lucide-icons/lucide/pull/3117)
- fix(icons): rotate `dumbbell` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3107](https://redirect.github.com/lucide-icons/lucide/pull/3107)
- fix(icons): changed `touchpad-off` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3118](https://redirect.github.com/lucide-icons/lucide/pull/3118)
- fix(icons): changed `bell-electric` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3139](https://redirect.github.com/lucide-icons/lucide/pull/3139)
- fix(icons): changed `menu` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3142](https://redirect.github.com/lucide-icons/lucide/pull/3142)
- fix(icons): changed `mail` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3144](https://redirect.github.com/lucide-icons/lucide/pull/3144)
- chore(pr-template): Adjust PR template by
[@&#8203;ericfennis](https://redirect.github.com/ericfennis) in
[https://github.com/lucide-icons/lucide/pull/3183](https://redirect.github.com/lucide-icons/lucide/pull/3183)
- feat(icons): added `soap-dispenser-droplet` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3088](https://redirect.github.com/lucide-icons/lucide/pull/3088)
- feat(icons): added `panda` icon by
[@&#8203;chessurisme](https://redirect.github.com/chessurisme) in
[https://github.com/lucide-icons/lucide/pull/2094](https://redirect.github.com/lucide-icons/lucide/pull/2094)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.506.0...0.507.0

</details>

<details>
<summary>nodejs/node (node)</summary>

###
[`v22.15.0`](https://redirect.github.com/nodejs/node/compare/v22.14.0...v22.15.0)

[Compare
Source](https://redirect.github.com/nodejs/node/compare/v22.14.0...v22.15.0)

###
[`v22.14.0`](https://redirect.github.com/nodejs/node/releases/tag/v22.14.0):
2025-02-11, Version 22.14.0 &#x27;Jod&#x27; (LTS), @&#8203;aduh95

[Compare
Source](https://redirect.github.com/nodejs/node/compare/v22.13.1...v22.14.0)

##### Notable Changes

-
\[[`82a9000e9e`](https://redirect.github.com/nodejs/node/commit/82a9000e9e)]
- **crypto**: update root certificates to NSS 3.107 (Node.js GitHub Bot)
[#&#8203;56566](https://redirect.github.com/nodejs/node/pull/56566)
-
\[[`b7fe54fc88`](https://redirect.github.com/nodejs/node/commit/b7fe54fc88)]
- **(SEMVER-MINOR)** **fs**: allow `exclude` option in globs to accept
glob patterns (Daeyeon Jeong)
[#&#8203;56489](https://redirect.github.com/nodejs/node/pull/56489)
-
\[[`3ac92ef607`](https://redirect.github.com/nodejs/node/commit/3ac92ef607)]
- **(SEMVER-MINOR)** **lib**: add typescript support to STDIN eval
(Marco Ippolito)
[#&#8203;56359](https://redirect.github.com/nodejs/node/pull/56359)
-
\[[`1614e8e7bc`](https://redirect.github.com/nodejs/node/commit/1614e8e7bc)]
- **(SEMVER-MINOR)** **module**: add ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX
(Marco Ippolito)
[#&#8203;56610](https://redirect.github.com/nodejs/node/pull/56610)
-
\[[`6d6cffa9cc`](https://redirect.github.com/nodejs/node/commit/6d6cffa9cc)]
- **(SEMVER-MINOR)** **module**: add `findPackageJSON` util (Jacob
Smith)
[#&#8203;55412](https://redirect.github.com/nodejs/node/pull/55412)
-
\[[`d35333ae18`](https://redirect.github.com/nodejs/node/commit/d35333ae18)]
- **(SEMVER-MINOR)** **process**: add process.ref() and process.unref()
methods (James M Snell)
[#&#8203;56400](https://redirect.github.com/nodejs/node/pull/56400)
-
\[[`07ff3ddcb5`](https://redirect.github.com/nodejs/node/commit/07ff3ddcb5)]
- **(SEMVER-MINOR)** **sqlite**: support TypedArray and DataView in
`StatementSync` (Alex Yang)
[#&#8203;56385](https://redirect.github.com/nodejs/node/pull/56385)
-
\[[`94d3fe1b62`](https://redirect.github.com/nodejs/node/commit/94d3fe1b62)]
- **(SEMVER-MINOR)** **src**: add --disable-sigusr1 to prevent signal
i/o thread (Rafael Gonzaga)
[#&#8203;56441](https://redirect.github.com/nodejs/node/pull/56441)
-
\[[`5afffb4415`](https://redirect.github.com/nodejs/node/commit/5afffb4415)]
- **(SEMVER-MINOR)** **src,worker**: add isInternalWorker (Carlos Espa)
[#&#8203;56469](https://redirect.github.com/nodejs/node/pull/56469)
-
\[[`697a851fb3`](https://redirect.github.com/nodejs/node/commit/697a851fb3)]
- **(SEMVER-MINOR)** **test_runner**: add
TestContext.prototype.waitFor() (Colin Ihrig)
[#&#8203;56595](https://redirect.github.com/nodejs/node/pull/56595)
-
\[[`047537b48c`](https://redirect.github.com/nodejs/node/commit/047537b48c)]
- **(SEMVER-MINOR)** **test_runner**: add t.assert.fileSnapshot() (Colin
Ihrig)
[#&#8203;56459](https://redirect.github.com/nodejs/node/pull/56459)
-
\[[`926cf84e95`](https://redirect.github.com/nodejs/node/commit/926cf84e95)]
- **(SEMVER-MINOR)** **test_runner**: add assert.register() API (Colin
Ihrig)
[#&#8203;56434](https://redirect.github.com/nodejs/node/pull/56434)
-
\[[`c658a8afdf`](https://redirect.github.com/nodejs/node/commit/c658a8afdf)]
- **(SEMVER-MINOR)** **worker**: add eval ts input (Marco Ippolito)
[#&#8203;56394](https://redirect.github.com/nodejs/node/pull/56394)

##### Commits

-
\[[`bad1ad8650`](https://redirect.github.com/nodejs/node/commit/bad1ad8650)]
- **assert**: make myers_diff function more performant (Giovanni Bucci)
[#&#8203;56303](https://redirect.github.com/nodejs/node/pull/56303)
-
\[[`e222e36f3b`](https://redirect.github.com/nodejs/node/commit/e222e36f3b)]
- **assert**: make partialDeepStrictEqual work with urls and File
prototypes (Giovanni Bucci)
[#&#8203;56231](https://redirect.github.com/nodejs/node/pull/56231)
-
\[[`e232789fe2`](https://redirect.github.com/nodejs/node/commit/e232789fe2)]
- **assert**: show diff when doing partial comparisons (Giovanni Bucci)
[#&#8203;56211](https://redirect.github.com/nodejs/node/pull/56211)
-
\[[`c99de1fdcf`](https://redirect.github.com/nodejs/node/commit/c99de1fdcf)]
- **assert**: make partialDeepStrictEqual throw when comparing \[0] with
\[-0] (Giovanni)
[#&#8203;56237](https://redirect.github.com/nodejs/node/pull/56237)
-
\[[`2386fd5840`](https://redirect.github.com/nodejs/node/commit/2386fd5840)]
- **benchmark**: add validateStream to styleText bench (Rafael Gonzaga)
[#&#8203;56556](https://redirect.github.com/nodejs/node/pull/56556)
-
\[[`b197dfa7ec`](https://redirect.github.com/nodejs/node/commit/b197dfa7ec)]
- **build**: fix GN build for ngtcp2 (Cheng)
[#&#8203;56300](https://redirect.github.com/nodejs/node/pull/56300)
-
\[[`2a3cdd34ff`](https://redirect.github.com/nodejs/node/commit/2a3cdd34ff)]
- **build**: test macos-13 on GitHub actions (Michaël Zasso)
[#&#8203;56307](https://redirect.github.com/nodejs/node/pull/56307)
-
\[[`12f716be0a`](https://redirect.github.com/nodejs/node/commit/12f716be0a)]
- **build**: build v8 with -fvisibility=hidden on macOS (Joyee Cheung)
[#&#8203;56275](https://redirect.github.com/nodejs/node/pull/56275)
-
\[[`c5ca15bd34`](https://redirect.github.com/nodejs/node/commit/c5ca15bd34)]
- **child_process**: fix parsing messages with splitted length field
(Maksim Gorkov)
[#&#8203;56106](https://redirect.github.com/nodejs/node/pull/56106)
-
\[[`8346b8fc2c`](https://redirect.github.com/nodejs/node/commit/8346b8fc2c)]
- **crypto**: add missing return value check (Michael Dawson)
[#&#8203;56615](https://redirect.github.com/nodejs/node/pull/56615)
-
\[[`82a9000e9e`](https://redirect.github.com/nodejs/node/commit/82a9000e9e)]
- **crypto**: update root certificates to NSS 3.107 (Node.js GitHub Bot)
[#&#8203;56566](https://redirect.github.com/nodejs/node/pull/56566)
-
\[[`890eef20a1`](https://redirect.github.com/nodejs/node/commit/890eef20a1)]
- **crypto**: fix checkPrime crash with large buffers (Santiago Gimeno)
[#&#8203;56559](https://redirect.github.com/nodejs/node/pull/56559)
-
\[[`5edb7b5e87`](https://redirect.github.com/nodejs/node/commit/5edb7b5e87)]
- **crypto**: fix warning of ignoring return value (Cheng)
[#&#8203;56527](https://redirect.github.com/nodejs/node/pull/56527)
-
\[[`b89f123a0b`](https://redirect.github.com/nodejs/node/commit/b89f123a0b)]
- **crypto**: make generatePrime/checkPrime interruptible (James M
Snell)
[#&#8203;56460](https://redirect.github.com/nodejs/node/pull/56460)
-
\[[`63c1859e01`](https://redirect.github.com/nodejs/node/commit/63c1859e01)]
- **deps**: update corepack to 0.31.0 (Node.js GitHub Bot)
[#&#8203;56795](https://redirect.github.com/nodejs/node/pull/56795)
-
\[[`a48430d4d3`](https://redirect.github.com/nodejs/node/commit/a48430d4d3)]
- **deps**: move inspector_protocol to deps (Chengzhong Wu)
[#&#8203;56649](https://redirect.github.com/nodejs/node/pull/56649)
-
\[[`74cccc824f`](https://redirect.github.com/nodejs/node/commit/74cccc824f)]
- **deps**: macro ENODATA is deprecated in libc++ (Cheng)
[#&#8203;56698](https://redirect.github.com/nodejs/node/pull/56698)
-
\[[`fa869ea0f2`](https://redirect.github.com/nodejs/node/commit/fa869ea0f2)]
- **deps**: fixup some minor coverity warnings (James M Snell)
[#&#8203;56612](https://redirect.github.com/nodejs/node/pull/56612)
-
\[[`1a4fa2b015`](https://redirect.github.com/nodejs/node/commit/1a4fa2b015)]
- **deps**: update amaro to 0.3.0 (Node.js GitHub Bot)
[#&#8203;56568](https://redirect.github.com/nodejs/node/pull/56568)
-
\[[`b47076fd82`](https://redirect.github.com/nodejs/node/commit/b47076fd82)]
- **deps**: update amaro to 0.2.2 (Node.js GitHub Bot)
[#&#8203;56568](https://redirect.github.com/nodejs/node/pull/56568)
-
\[[`46bd4b8731`](https://redirect.github.com/nodejs/node/commit/46bd4b8731)]
- **deps**: update simdutf to 6.0.3 (Node.js GitHub Bot)
[#&#8203;56567](https://redirect.github.com/nodejs/node/pull/56567)
-
\[[`8ead9c693b`](https://redirect.github.com/nodejs/node/commit/8ead9c693b)]
- **deps**: update simdutf to 5.7.2 (Node.js GitHub Bot)
[#&#8203;56388](https://redirect.github.com/nodejs/node/pull/56388)
-
\[[`18d4b502af`](https://redirect.github.com/nodejs/node/commit/18d4b502af)]
- **deps**: update amaro to 0.2.1 (Node.js GitHub Bot)
[#&#8203;56390](https://redirect.github.com/nodejs/node/pull/56390)
-
\[[`d938d7cc86`](https://redirect.github.com/nodejs/node/commit/d938d7cc86)]
- **deps**: update googletest to
[`7d76a23`](https://redirect.github.com/nodejs/node/commit/7d76a23)
(Node.js GitHub Bot)
[#&#8203;56387](https://redirect.github.com/nodejs/node/pull/56387)
-
\[[`9761e7dccb`](https://redirect.github.com/nodejs/node/commit/9761e7dccb)]
- **deps**: update googletest to
[`e54519b`](https://redirect.github.com/nodejs/node/commit/e54519b)
(Node.js GitHub Bot)
[#&#8203;56370](https://redirect.github.com/nodejs/node/pull/56370)
-
\[[`8319dc6bc5`](https://redirect.github.com/nodejs/node/commit/8319dc6bc5)]
- **deps**: update ngtcp2 to 1.10.0 (Node.js GitHub Bot)
[#&#8203;56334](https://redirect.github.com/nodejs/node/pull/56334)
-
\[[`6eacd19d6a`](https://redirect.github.com/nodejs/node/commit/6eacd19d6a)]
- **deps**: update simdutf to 5.7.0 (Node.js GitHub Bot)
[#&#8203;56332](https://redirect.github.com/nodejs/node/pull/56332)
-
\[[`28bec2dda3`](https://redirect.github.com/nodejs/node/commit/28bec2dda3)]
- **diagnostics_channel**: capture console messages (Stephen Belanger)
[#&#8203;56292](https://redirect.github.com/nodejs/node/pull/56292)
-
\[[`d519d33502`](https://redirect.github.com/nodejs/node/commit/d519d33502)]
- **doc**: update macOS and Xcode versions for releases (Michaël Zasso)
[#&#8203;56337](https://redirect.github.com/nodejs/node/pull/56337)
-
\[[`fcfe650507`](https://redirect.github.com/nodejs/node/commit/fcfe650507)]
- **doc**: add note for features using `InternalWorker` with permission
model (Antoine du Hamel)
[#&#8203;56706](https://redirect.github.com/nodejs/node/pull/56706)
-
\[[`efbba182b5`](https://redirect.github.com/nodejs/node/commit/efbba182b5)]
- **doc**: add entry to changelog about SQLite Session Extension (Bart
Louwers)
[#&#8203;56318](https://redirect.github.com/nodejs/node/pull/56318)
-
\[[`31bf9c7dd9`](https://redirect.github.com/nodejs/node/commit/31bf9c7dd9)]
- **doc**: move anatoli to emeritus (Michael Dawson)
[#&#8203;56592](https://redirect.github.com/nodejs/node/pull/56592)
-
\[[`6096e38c7c`](https://redirect.github.com/nodejs/node/commit/6096e38c7c)]
- **doc**: fix styles of the expandable TOC (Antoine du Hamel)
[#&#8203;56755](https://redirect.github.com/nodejs/node/pull/56755)
-
\[[`d423638281`](https://redirect.github.com/nodejs/node/commit/d423638281)]
- **doc**: add "Skip to content" button (Antoine du Hamel)
[#&#8203;56750](https://redirect.github.com/nodejs/node/pull/56750)
-
\[[`edeb157d75`](https://redirect.github.com/nodejs/node/commit/edeb157d75)]
- **doc**: improve accessibility of expandable lists (Antoine du Hamel)
[#&#8203;56749](https://redirect.github.com/nodejs/node/pull/56749)
-
\[[`1a79e87687`](https://redirect.github.com/nodejs/node/commit/1a79e87687)]
- **doc**: add note regarding commit message trailers (Dario Piotrowicz)
[#&#8203;56736](https://redirect.github.com/nodejs/node/pull/56736)
-
\[[`927c7e47e4`](https://redirect.github.com/nodejs/node/commit/927c7e47e4)]
- **doc**: fix typo in example code for util.styleText (Robin Mehner)
[#&#8203;56720](https://redirect.github.com/nodejs/node/pull/56720)
-
\[[`fade522538`](https://redirect.github.com/nodejs/node/commit/fade522538)]
- **doc**: fix inconsistencies in `WeakSet` and `WeakMap` comparison
details (Shreyans Pathak)
[#&#8203;56683](https://redirect.github.com/nodejs/node/pull/56683)
-
\[[`55533bf147`](https://redirect.github.com/nodejs/node/commit/55533bf147)]
- **doc**: add RafaelGSS as latest sec release stewards (Rafael Gonzaga)
[#&#8203;56682](https://redirect.github.com/nodejs/node/pull/56682)
-
\[[`8e978bdee1`](https://redirect.github.com/nodejs/node/commit/8e978bdee1)]
- **doc**: clarify cjs/esm diff in `queueMicrotask()` vs
`process.nextTick()` (Dario Piotrowicz)
[#&#8203;56659](https://redirect.github.com/nodejs/node/pull/56659)
-
\[[`ae360c30dc`](https://redirect.github.com/nodejs/node/commit/ae360c30dc)]
- **doc**: `WeakSet` and `WeakMap` comparison details (Shreyans Pathak)
[#&#8203;56648](https://redirect.github.com/nodejs/node/pull/56648)
-
\[[`acd2a2fda5`](https://redirect.github.com/nodejs/node/commit/acd2a2fda5)]
- **doc**: mention prepare --security (Rafael Gonzaga)
[#&#8203;56617](https://redirect.github.com/nodejs/node/pull/56617)
-
\[[`d3c0a2831d`](https://redirect.github.com/nodejs/node/commit/d3c0a2831d)]
- **doc**: tweak info on reposts in ambassador program (Michael Dawson)
[#&#8203;56589](https://redirect.github.com/nodejs/node/pull/56589)
-
\[[`3299505b49`](https://redirect.github.com/nodejs/node/commit/3299505b49)]
- **doc**: add type stripping to ambassadors program (Marco Ippolito)
[#&#8203;56598](https://redirect.github.com/nodejs/node/pull/56598)
-
\[[`b1a6ffa4e4`](https://redirect.github.com/nodejs/node/commit/b1a6ffa4e4)]
- **doc**: improve internal documentation on built-in snapshot (Joyee
Cheung)
[#&#8203;56505](https://redirect.github.com/nodejs/node/pull/56505)
-
\[[`1641a28930`](https://redirect.github.com/nodejs/node/commit/1641a28930)]
- **doc**: document CLI way to open the nodejs/bluesky PR (Antoine du
Hamel)
[#&#8203;56506](https://redirect.github.com/nodejs/node/pull/56506)
-
\[[`2042628fda`](https://redirect.github.com/nodejs/node/commit/2042628fda)]
- **doc**: add section about using npx with permission model (Rafael
Gonzaga)
[#&#8203;56539](https://redirect.github.com/nodejs/node/pull/56539)
-
\[[`ace19a0263`](https://redirect.github.com/nodejs/node/commit/ace19a0263)]
- **doc**: update gcc-version for ubuntu-lts (Kunal Kumar)
[#&#8203;56553](https://redirect.github.com/nodejs/node/pull/56553)
-
\[[`4aa57b50f8`](https://redirect.github.com/nodejs/node/commit/4aa57b50f8)]
- **doc**: fix parentheses in options (Tobias Nießen)
[#&#8203;56563](https://redirect.github.com/nodejs/node/pull/56563)
-
\[[`b40b01b4d3`](https://redirect.github.com/nodejs/node/commit/b40b01b4d3)]
- **doc**: include CVE to EOL lines as sec release process (Rafael
Gonzaga)
[#&#8203;56520](https://redirect.github.com/nodejs/node/pull/56520)
-
\[[`6701360113`](https://redirect.github.com/nodejs/node/commit/6701360113)]
- **doc**: add esm examples to node:trace_events (Alfredo González)
[#&#8203;56514](https://redirect.github.com/nodejs/node/pull/56514)
-
\[[`d3207cca3e`](https://redirect.github.com/nodejs/node/commit/d3207cca3e)]
- **doc**: add message for Ambassadors to promote (Michael Dawson)
[#&#8203;56235](https://redirect.github.com/nodejs/node/pull/56235)
-
\[[`97ece4ae06`](https://redirect.github.com/nodejs/node/commit/97ece4ae06)]
- **doc**: allow request for TSC reviews via the GitHub UI (Antoine du
Hamel)
[#&#8203;56493](https://redirect.github.com/nodejs/node/pull/56493)
-
\[[`03f25055ab`](https://redirect.github.com/nodejs/node/commit/03f25055ab)]
- **doc**: add example for piping ReadableStream (Gabriel Schulhof)
[#&#8203;56415](https://redirect.github.com/nodejs/node/pull/56415)
-
\[[`516d07482c`](https://redirect.github.com/nodejs/node/commit/516d07482c)]
- **doc**: expand description of `parseArg`'s `default` (Kevin Gibbons)
[#&#8203;54431](https://redirect.github.com/nodejs/node/pull/54431)
-
\[[`a6491effcb`](https://redirect.github.com/nodejs/node/commit/a6491effcb)]
- **doc**: use `<ul>` instead of `<ol>` in `SECURITY.md` (Antoine du
Hamel)
[#&#8203;56346](https://redirect.github.com/nodejs/node/pull/56346)
-
\[[`e4ec134b21`](https://redirect.github.com/nodejs/node/commit/e4ec134b21)]
- **doc**: clarify that WASM is trusted (Matteo Collina)
[#&#8203;56345](https://redirect.github.com/nodejs/node/pull/56345)
-
\[[`0f7aed8a59`](https://redirect.github.com/nodejs/node/commit/0f7aed8a59)]
- **doc**: fix the `crc32` documentation (Kevin Toshihiro Uehara)
[#&#8203;55898](https://redirect.github.com/nodejs/node/pull/55898)
-
\[[`721104a296`](https://redirect.github.com/nodejs/node/commit/721104a296)]
- **doc**: fix links in `module.md` (Antoine du Hamel)
[#&#8203;56283](https://redirect.github.com/nodejs/node/pull/56283)
-
\[[`928540d792`](https://redirect.github.com/nodejs/node/commit/928540d792)]
- **doc**: fix typos (Nathan Baulch)
[#&#8203;55066](https://redirect.github.com/nodejs/node/pull/55066)
-
\[[`e69d35f03b`](https://redirect.github.com/nodejs/node/commit/e69d35f03b)]
- **doc**: add history info for Permission Model (Antoine du Hamel)
[#&#8203;56707](https://redirect.github.com/nodejs/node/pull/56707)
-
\[[`c6fd867ab5`](https://redirect.github.com/nodejs/node/commit/c6fd867ab5)]
- **esm**: fix jsdoc type refs to `ModuleJobBase` in esm/loader (Jacob
Smith)
[#&#8203;56499](https://redirect.github.com/nodejs/node/pull/56499)
-
\[[`9cf9046bd7`](https://redirect.github.com/nodejs/node/commit/9cf9046bd7)]
- ***Revert*** "**events**: add hasEventListener util for validate"
(origranot)
[#&#8203;56282](https://redirect.github.com/nodejs/node/pull/56282)
-
\[[`b7fe54fc88`](https://redirect.github.com/nodejs/node/commit/b7fe54fc88)]
- **(SEMVER-MINOR)** **fs**: allow `exclude` option in globs to accept
glob patterns (Daeyeon Jeong)
[#&#8203;56489](https://redirect.github.com/nodejs/node/pull/56489)
-
\[[`6ca27c2a59`](https://redirect.github.com/nodejs/node/commit/6ca27c2a59)]
- **http2**: omit server name when HTTP2 host is IP address (islandryu)
[#&#8203;56530](https://redirect.github.com/nodejs/node/pull/56530)
-
\[[`9f1fa199bf`](https://redirect.github.com/nodejs/node/commit/9f1fa199bf)]
- **inspector**: roll inspector_protocol (Chengzhong Wu)
[#&#8203;56649](https://redirect.github.com/nodejs/node/pull/56649)
-
\[[`0dae4bb3ab`](https://redirect.github.com/nodejs/node/commit/0dae4bb3ab)]
- **inspector**: add undici http tracking support (Chengzhong Wu)
[#&#8203;56488](https://redirect.github.com/nodejs/node/pull/56488)
-
\[[`2c6124cec4`](https://redirect.github.com/nodejs/node/commit/2c6124cec4)]
- **inspector**: report loadingFinished until the response data is
consumed (Chengzhong Wu)
[#&#8203;56372](https://redirect.github.com/nodejs/node/pull/56372)
-
\[[`96ec862ce2`](https://redirect.github.com/nodejs/node/commit/96ec862ce2)]
- **lib**: refactor execution.js (Marco Ippolito)
[#&#8203;56358](https://redirect.github.com/nodejs/node/pull/56358)
-
\[[`3ac92ef607`](https://redirect.github.com/nodejs/node/commit/3ac92ef607)]
- **(SEMVER-MINOR)** **lib**: add typescript support to STDIN eval
(Marco Ippolito)
[#&#8203;56359](https://redirect.github.com/nodejs/node/pull/56359)
-
\[[`d5bf3db0cf`](https://redirect.github.com/nodejs/node/commit/d5bf3db0cf)]
- **lib**: allow skipping source maps in node_modules (Chengzhong Wu)
[#&#8203;56639](https://redirect.github.com/nodejs/node/pull/56639)
-
\[[`d33eaf2bcb`](https://redirect.github.com/nodejs/node/commit/d33eaf2bcb)]
- **lib**: ensure FORCE_COLOR forces color output in non-TTY
environments (Pietro Marchini)
[#&#8203;55404](https://redirect.github.com/nodejs/node/pull/55404)
-
\[[`dc003218a8`](https://redirect.github.com/nodejs/node/commit/dc003218a8)]
- **lib**: optimize `prepareStackTrace` on builtin frames (Chengzhong
Wu) [#&#8203;56299](https://redirect.github.com/nodejs/node/pull/56299)
-
\[[`df06524863`](https://redirect.github.com/nodejs/node/commit/df06524863)]
- **lib**: suppress source map lookup exceptions (Chengzhong Wu)
[#&#8203;56299](https://redirect.github.com/nodejs/node/pull/56299)
-
\[[`35335a5a66`](https://redirect.github.com/nodejs/node/commit/35335a5a66)]
- **meta**: move one or more collaborators to emeritus (Node.js GitHub
Bot) [#&#8203;56580](https://redirect.github.com/nodejs/node/pull/56580)
-
\[[`1faabdb150`](https://redirect.github.com/nodejs/node/commit/1faabdb150)]
- **meta**: add codeowners of security release document (Rafael Gonzaga)
[#&#8203;56521](https://redirect.github.com/nodejs/node/pull/56521)
-
\[[`b4ece22ef5`](https://redirect.github.com/nodejs/node/commit/b4ece22ef5)]
- **meta**: move one or more collaborators to emeritus (Node.js GitHub
Bot) [#&#8203;56342](https://redirect.github.com/nodejs/node/pull/56342)
-
\[[`9ec67e7ce0`](https://redirect.github.com/nodejs/node/commit/9ec67e7ce0)]
- **meta**: move MoLow to TSC regular member (Moshe Atlow)
[#&#8203;56276](https://redirect.github.com/nodejs/node/pull/56276)
-
\[[`bae4b2e20a`](https://redirect.github.com/nodejs/node/commit/bae4b2e20a)]
- **module**: use more defensive code when handling SWC errors (Antoine
du Hamel)
[#&#8203;56646](https://redirect.github.com/nodejs/node/pull/56646)
-
\[[`1614e8e7bc`](https://redirect.github.com/nodejs/node/commit/1614e8e7bc)]
- **(SEMVER-MINOR)** **module**: add ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX
(Marco Ippolito)
[#&#8203;56610](https://redirect.github.com/nodejs/node/pull/56610)
-
\[[`174d88eab1`](https://redirect.github.com/nodejs/node/commit/174d88eab1)]
- **module**: support eval with ts syntax detection (Marco Ippolito)
[#&#8203;56285](https://redirect.github.com/nodejs/node/pull/56285)
-
\[[`299d6fa829`](https://redirect.github.com/nodejs/node/commit/299d6fa829)]
- **module**: fix jsdoc for `format` parameter in cjs/loader (pacexy)
[#&#8203;56501](https://redirect.github.com/nodejs/node/pull/56501)
-
\[[`0307e4dd59`](https://redirect.github.com/nodejs/node/commit/0307e4dd59)]
- **module**: unify TypeScript and .mjs handling in CommonJS (Joyee
Cheung)
[#&#8203;55590](https://redirect.github.com/nodejs/node/pull/55590)
-
\[[`1f4f9be93d`](https://redirect.github.com/nodejs/node/commit/1f4f9be93d)]
- **module**: fix async resolution error within the sync
`findPackageJSON` (Jacob Smith)
[#&#8203;56382](https://redirect.github.com/nodejs/node/pull/56382)
-
\[[`bbedffa0f0`](https://redirect.github.com/nodejs/node/commit/bbedffa0f0)]
- **module**: simplify `findPackageJSON` implementation (Antoine du
Hamel)
[#&#8203;55543](https://redirect.github.com/nodejs/node/pull/55543)
-
\[[`6d6cffa9cc`](https://redirect.github.com/nodejs/node/commit/6d6cffa9cc)]
- **(SEMVER-MINOR)** **module**: add `findPackageJSON` util (Jacob
Smith)
[#&#8203;55412](https://redirect.github.com/nodejs/node/pull/55412)
-
\[[`cd7ce18233`](https://redirect.github.com/nodejs/node/commit/cd7ce18233)]
- **module**: fix bad `require.resolve` with option paths for `.` and
`..` (Dario Piotrowicz)
[#&#8203;56735](https://redirect.github.com/nodejs/node/pull/56735)
-
\[[`152df4da21`](https://redirect.github.com/nodejs/node/commit/152df4da21)]
- **module**: rethrow amaro error message (Marco Ippolito)
[#&#8203;56568](https://redirect.github.com/nodejs/node/pull/56568)
-
\[[`acba5dc87e`](https://redirect.github.com/nodejs/node/commit/acba5dc87e)]
- **module**: use buffer.toString base64 (Chengzhong Wu)
[#&#8203;56315](https://redirect.github.com/nodejs/node/pull/56315)
-
\[[`01e69be8ff`](https://redirect.github.com/nodejs/node/commit/01e69be8ff)]
- **node-api**: define version 10 (Gabriel Schulhof)
[#&#8203;55676](https://redirect.github.com/nodejs/node/pull/55676)
-
\[[`724524528e`](https://redirect.github.com/nodejs/node/commit/724524528e)]
- **node-api**: remove deprecated attribute from napi_module_register
(Vladimir Morozov)
[#&#8203;56162](https://redirect.github.com/nodejs/node/pull/56162)
-
\[[`c78e11064f`](https://redirect.github.com/nodejs/node/commit/c78e11064f)]
- **process**: remove support for undocumented symbol (Antoine du Hamel)
[#&#8203;56552](https://redirect.github.com/nodejs/node/pull/56552)
-
\[[`3f69b18a23`](https://redirect.github.com/nodejs/node/commit/3f69b18a23)]
- **process**: fix symbol key and mark experimental new `node:process`
methods (Antoine du Hamel)
[#&#8203;56517](https://redirect.github.com/nodejs/node/pull/56517)
-
\[[`d35333ae18`](https://redirect.github.com/nodejs/node/commit/d35333ae18)]
- **(SEMVER-MINOR)** **process**: add process.ref() and process.unref()
methods (James M Snell)
[#&#8203;56400](https://redirect.github.com/nodejs/node/pull/56400)
-
\[[`fa49f0f7d5`](https://redirect.github.com/nodejs/node/commit/fa49f0f7d5)]
- **punycode**: limit deprecation warning (Colin Ihrig)
[#&#8203;56632](https://redirect.github.com/nodejs/node/pull/56632)
-
\[[`d77c7073b7`](https://redirect.github.com/nodejs/node/commit/d77c7073b7)]
- **sqlite**: disable memstatus APIs at build time (Colin Ihrig)
[#&#8203;56541](https://redirect.github.com/nodejs/node/pull/56541)
-
\[[`07ff3ddcb5`](https://redirect.github.com/nodejs/node/commit/07ff3ddcb5)]
- **(SEMVER-MINOR)** **sqlite**: support TypedArray and DataView in
`StatementSync` (Alex Yang)
[#&#8203;56385](https://redirect.github.com/nodejs/node/pull/56385)
-
\[[`b6c2e91365`](https://redirect.github.com/nodejs/node/commit/b6c2e91365)]
- **sqlite**: enable SQL math functions (Colin Ihrig)
[#&#8203;56447](https://redirect.github.com/nodejs/node/pull/56447)
-
\[[`3462263e8b`](https://redirect.github.com/nodejs/node/commit/3462263e8b)]
- **sqlite**: pass conflict type to conflict resolution handler (Bart
Louwers)
[#&#8203;56352](https://redirect.github.com/nodejs/node/pull/56352)
-
\[[`89ba3af743`](https://redirect.github.com/nodejs/node/commit/89ba3af743)]
- **src**: add nullptr handling from X509\_STORE_new() (Burkov Egor)
[#&#8203;56700](https://redirect.github.com/nodejs/node/pull/56700)
-
\[[`89a7c82e0c`](https://redirect.github.com/nodejs/node/commit/89a7c82e0c)]
- **src**: add default value for RSACipherConfig mode field (Burkov
Egor)
[#&#8203;56701](https://redirect.github.com/nodejs/node/pull/56701)
-
\[[`7bae51e62e`](https://redirect.github.com/nodejs/node/commit/7bae51e62e)]
- **src**: fix build with GCC 15 (tjuhaszrh)
[#&#8203;56740](https://redirect.github.com/nodejs/node/pull/56740)
-
\[[`432a4b8bd6`](https://redirect.github.com/nodejs/node/commit/432a4b8bd6)]
- **src**: fix to generate path from wchar_t via wstring (yamachu)
[#&#8203;56696](https://redirect.github.com/nodejs/node/pull/56696)
-
\[[`8c9eaf82f0`](https://redirect.github.com/nodejs/node/commit/8c9eaf82f0)]
- **src**: initialize FSReqWrapSync in path that uses it (Michaël Zasso)
[#&#8203;56613](https://redirect.github.com/nodejs/node/pull/56613)
-
\[[`bcdb42d40b`](https://redirect.github.com/nodejs/node/commit/bcdb42d40b)]
- **src**: handle duplicate paths granted (Rafael Gonzaga)
[#&#8203;56591](https://redirect.github.com/nodejs/node/pull/56591)
-
\[[`d6a7acc207`](https://redirect.github.com/nodejs/node/commit/d6a7acc207)]
- **src**: update ECKeyPointer in ncrypto (James M Snell)
[#&#8203;56526](https://redirect.github.com/nodejs/node/pull/56526)
-
\[[`01922f8b1f`](https://redirect.github.com/nodejs/node/commit/01922f8b1f)]
- **src**: update ECPointPointer in ncrypto (James M Snell)
[#&#8203;56526](https://redirect.github.com/nodejs/node/pull/56526)
-
\[[`2a3a36eceb`](https://redirect.github.com/nodejs/node/commit/2a3a36eceb)]
- **src**: update ECGroupPointer in ncrypto (James M Snell)
[#&#8203;56526](https://redirect.github.com/nodejs/node/pull/56526)
-
\[[`67c10cdacb`](https://redirect.github.com/nodejs/node/commit/67c10cdacb)]
- **src**: update ECDASSigPointer implementation in ncrypto (James M
Snell)
[#&#8203;56526](https://redirect.github.com/nodejs/node/pull/56526)
-
\[[`17f931c68b`](https://redirect.github.com/nodejs/node/commit/17f931c68b)]
- **src**: cleaning up more crypto internals for ncrypto (James M Snell)
[#&#8203;56526](https://redirect.github.com/nodejs/node/pull/56526)
-
\[[`94d3fe1b62`](https://redirect.github.com/nodejs/node/commit/94d3fe1b62)]
- **(SEMVER-MINOR)** **src**: add --disable-sigusr1 to prevent signal
i/o thread (Rafael Gonzaga)
[#&#8203;56441](https://redirect.github.com/nodejs/node/pull/56441)
-
\[[`6594ee8dff`](https://redirect.github.com/nodejs/node/commit/6594ee8dff)]
- **src**: fix undefined script name in error source (Chengzhong Wu)
[#&#8203;56502](https://redirect.github.com/nodejs/node/pull/56502)
-
\[[`b46bad3e91`](https://redirect.github.com/nodejs/node/commit/b46bad3e91)]
- **src**: refactor --trace-env to reuse option selection and handling
(Joyee Cheung)
[#&#8203;56293](https://redirect.github.com/nodejs/node/pull/56293)
-
\[[`76921b822b`](https://redirect.github.com/nodejs/node/commit/76921b822b)]
- **src**: minor cleanups on OneByteString usage (James M Snell)
[#&#8203;56482](https://redirect.github.com/nodejs/node/pull/56482)
-
\[[`3f0d1dd4fe`](https://redirect.github.com/nodejs/node/commit/3f0d1dd4fe)]
- **src**: move more crypto impl detail to ncrypto dep (James M Snell)
[#&#8203;56421](https://redirect.github.com/nodejs/node/pull/56421)
-
\[[`04f623b283`](https://redirect.github.com/nodejs/node/commit/04f623b283)]
- **src**: fixup more ToLocalChecked uses in node_file (James M Snell)
[#&#8203;56484](https://redirect.github.com/nodejs/node/pull/56484)
-
\[[`5aa436f5a1`](https://redirect.github.com/nodejs/node/commit/5aa436f5a1)]
- **src**: make some minor ToLocalChecked cleanups (James M Snell)
[#&#8203;56483](https://redirect.github.com/nodejs/node/pull/56483)
-
\[[`6eec5e7ec2`](https://redirect.github.com/nodejs/node/commit/6eec5e7ec2)]
- **src**: lock the thread properly in snapshot builder (Joyee Cheung)
[#&#8203;56327](https://redirect.github.com/nodejs/node/pull/56327)
-
\[[`5614993968`](https://redirect.github.com/nodejs/node/commit/5614993968)]
- **src**: drain platform tasks before creating startup snapshot
(Chengzhong Wu)
[#&#8203;56403](https://redirect.github.com/nodejs/node/pull/56403)
-
\[[`48493e9fd5`](https://redirect.github.com/nodejs/node/commit/48493e9fd5)]
- **src**: use LocalVector in more places (James M Snell)
[#&#8203;56457](https://redirect.github.com/nodejs/node/pull/56457)
-
\[[`7e5ea0681e`](https://redirect.github.com/nodejs/node/commit/7e5ea0681e)]
- **src**: use v8::LocalVector consistently with other minor cleanups
(James M Snell)
[#&#8203;56417](https://redirect.github.com/nodejs/node/pull/56417)
-
\[[`ad3d857f2b`](https://redirect.github.com/nodejs/node/commit/ad3d857f2b)]
- **src**: use starts_with in fs_permission.cc (ishabi)
[#&#8203;55811](https://redirect.github.com/nodejs/node/pull/55811)
-
\[[`5afffb4415`](https://redirect.github.com/nodejs/node/commit/5afffb4415)]
- **(SEMVER-MINOR)** **src,worker**: add isInternalWorker (Carlos Espa)
[#&#8203;56469](https://redirect.github.com/nodejs/node/pull/56469)
-
\[[`7d1676e72e`](https://redirect.github.com/nodejs/node/commit/7d1676e72e)]
- **stream**: fix typo in ReadableStreamBYOBReader.readIntoRequests
(Mattias Buelens)
[#&#8203;56560](https://redirect.github.com/nodejs/node/pull/56560)
-
\[[`e658ea6b26`](https://redirect.github.com/nodejs/node/commit/e658ea6b26)]
- **stream**: validate undefined sizeAlgorithm in WritableStream (Jason
Zhang)
[#&#8203;56067](https://redirect.github.com/nodejs/node/pull/56067)
-
\[[`e4f133c20c`](https://redirect.github.com/nodejs/node/commit/e4f133c20c)]
- **test**: add ts eval snapshots (Marco Ippolito)
[#&#8203;56358](https://redirect.github.com/nodejs/node/pull/56358)
-
\[[`f041742400`](https://redirect.github.com/nodejs/node/commit/f041742400)]
- **test**: remove empty lines from snapshots (Marco Ippolito)
[#&#8203;56358](https://redirect.github.com/nodejs/node/pull/56358)
-
\[[`801cde91f6`](https://redirect.github.com/nodejs/node/commit/801cde91f6)]
- **test**: reduce number of written chunks (Luigi Pinca)
[#&#8203;56757](https://redirect.github.com/nodejs/node/pull/56757)
-
\[[`6fdf1879ab`](https://redirect.github.com/nodejs/node/commit/6fdf1879ab)]
- **test**: fix invalid common.mustSucceed() usage (Luigi Pinca)
[#&#8203;56756](https://redirect.github.com/nodejs/node/pull/56756)
-
\[[`d2bfbfa364`](https://redirect.github.com/nodejs/node/commit/d2bfbfa364)]
- **test**: use strict mode in global setters test (Rich Trott)
[#&#8203;56742](https://redirect.github.com/nodejs/node/pull/56742)
-
\[[`5c030da42f`](https://redirect.github.com/nodejs/node/commit/5c030da42f)]
- **test**: cleanup and simplify test-crypto-aes-wrap (James M Snell)
[#&#8203;56748](https://redirect.github.com/nodejs/node/pull/56748)
-
\[[`f1442d6eaf`](https://redirect.github.com/nodejs/node/commit/f1442d6eaf)]
- **test**: do not use common.isMainThread (Luigi Pinca)
[#&#8203;56768](https://redirect.github.com/nodejs/node/pull/56768)
-
\[[`49405bd9e7`](https://redirect.github.com/nodejs/node/commit/49405bd9e7)]
- **test**: make some requires lazy in common/index (James M Snell)
[#&#8203;56715](https://redirect.github.com/nodejs/node/pull/56715)
-
\[[`52ef376788`](https://redirect.github.com/nodejs/node/commit/52ef376788)]
- **test**: add test that uses multibyte for path and resolves modules
(yamachu)
[#&#8203;56696](https://redirect.github.com/nodejs/node/pull/56696)
-
\[[`b811dea85a`](https://redirect.github.com/nodejs/node/commit/b811dea85a)]
- **test**: replace more uses of `global` with `globalThis` (James M
Snell)
[#&#8203;56712](https://redirect.github.com/nodejs/node/pull/56712)
-
\[[`eb97076199`](https://redirect.github.com/nodejs/node/commit/eb97076199)]
- **test**: make common/index slightly less node.js specific (James M
Snell)
[#&#8203;56712](https://redirect.github.com/nodejs/node/pull/56712)
-
\[[`1795202d19`](https://redirect.github.com/nodejs/node/commit/1795202d19)]
- **test**: rely less on duplicative common test harness utilities
(James M Snell)
[#&#8203;56712](https://redirect.github.com/nodejs/node/pull/56712)
-
\[[`5be29a274e`](https://redirect.github.com/nodejs/node/commit/5be29a274e)]
- **test**: simplify common/index.js (James M Snell)
[#&#8203;56712](https://redirect.github.com/nodejs/node/pull/56712)
-
\[[`92e99780f0`](https://redirect.github.com/nodejs/node/commit/92e99780f0)]
- **test**: move hasMultiLocalhost to common/net (James M Snell)
[#&#8203;56716](https://redirect.github.com/nodejs/node/pull/56716)
-
\[[`1c3204a4cc`](https://redirect.github.com/nodejs/node/commit/1c3204a4cc)]
- **test**: move crypto related common utilities in common/crypto (James
M Snell)
[#&#8203;56714](https://redirect.github.com/nodejs/node/pull/56714)
-
\[[`fe79d63be0`](https://redirect.github.com/nodejs/node/commit/fe79d63be0)]
- **test**: add missing test for env file (Jonas)
[#&#8203;56642](https://redirect.github.com/nodejs/node/pull/56642)
-
\[[`e08af61537`](https://redirect.github.com/nodejs/node/commit/e08af61537)]
- **test**: enforce strict mode in test-zlib-const (Rich Trott)
[#&#8203;56689](https://redirect.github.com/nodejs/node/pull/56689)
-
\[[`c96792d7f8`](https://redirect.github.com/nodejs/node/commit/c96792d7f8)]
- **test**: fix localization data for ICU 74.2 (Antoine du Hamel)
[#&#8203;56661](https://redirect.github.com/nodejs/node/pull/56661)
-
\[[`48b72f1195`](https://redirect.github.com/nodejs/node/commit/48b72f1195)]
- **test**: use --permission instead of --experimental-permission
(Rafael Gonzaga)
[#&#8203;56685](https://redirect.github.com/nodejs/node/pull/56685)
-
\[[`de81d90fce`](https://redirect.github.com/nodejs/node/commit/de81d90fce)]
- **test**: test-stream-compose.js doesn't need internals (Meghan Denny)
[#&#8203;56619](https://redirect.github.com/nodejs/node/pull/56619)
-
\[[`f5b8499ad0`](https://redirect.github.com/nodejs/node/commit/f5b8499ad0)]
- **test**: add maxCount and gcOptions to gcUntil() (Joyee Cheung)
[#&#8203;56522](https://redirect.github.com/nodejs/node/pull/56522)
-
\[[`d9e5a81041`](https://redirect.github.com/nodejs/node/commit/d9e5a81041)]
- **test**: add line break at end of file (Rafael Gonzaga)
[#&#8203;56588](https://redirect.github.com/nodejs/node/pull/56588)
-
\[[`59be346fbf`](https://redirect.github.com/nodejs/node/commit/59be346fbf)]
- **test**: mark test-worker-prof as flaky on smartos (Joyee Cheung)
[#&#8203;56583](https://redirect.github.com/nodejs/node/pull/56583)
-
\[[`12a2cae9e5`](https://redirect.github.com/nodejs/node/commit/12a2cae9e5)]
- **test**: update test-child-process-bad-stdio to use node:test (Colin
Ihrig)
[#&#8203;56562](https://redirect.github.com/nodejs/node/pull/56562)
-
\[[`2dc4a30e19`](https://redirect.github.com/nodejs/node/commit/2dc4a30e19)]
- **test**: disable openssl 3.4.0 incompatible tests (Jelle van der Waa)
[#&#8203;56160](https://redirect.github.com/nodejs/node/pull/56160)
-
\[[`1950fbf51d`](https://redirect.github.com/nodejs/node/commit/1950fbf51d)]
- **test**: make test-crypto-hash compatible with OpenSSL > 3.4.0 (Jelle
van der Waa)
[#&#8203;56160](https://redirect.github.com/nodejs/node/pull/56160)
-
\[[`a533420a91`](https://redirect.github.com/nodejs/node/commit/a533420a91)]
- **test**: clarify fork inherit permission flags (Rafael Gonzaga)
[#&#8203;56523](https://redirect.github.com/nodejs/node/pull/56523)
-
\[[`697e799dc1`](https://redirect.github.com/nodejs/node/commit/697e799dc1)]
- **test**: add error only reporter for node:test (Carlos Espa)
[#&#8203;56438](https://redirect.github.com/nodejs/node/pull/56438)
-
\[[`4844fa212d`](https://redirect.github.com/nodejs/node/commit/4844fa212d)]
- **test**: mark test-http-server-request-timeouts-mixed as flaky (Joyee
Cheung)
[#&#8203;56503](https://redirect.github.com/nodejs/node/pull/56503)
-
\[[`843c2389b9`](https://redirect.github.com/nodejs/node/commit/843c2389b9)]
- **test**: update error code in tls-psk-circuit for for OpenSSL 3.4
(sebastianas)
[#&#8203;56420](https://redirect.github.com/nodejs/node/pull/56420)
-
\[[`ccb2ddbd83`](https://redirect.github.com/nodejs/node/commit/ccb2ddbd83)]
- **test**: update compiled sqlite tests to match other tests (Colin
Ihrig)
[#&#8203;56446](https://redirect.github.com/nodejs/node/pull/56446)
-
\[[`b40f50324d`](https://redirect.github.com/nodejs/node/commit/b40f50324d)]
- **test**: add initial test426 coverage (Chengzhong Wu)
[#&#8203;56436](https://redirect.github.com/nodejs/node/pull/56436)
-
\[[`059f81e4fd`](https://redirect.github.com/nodejs/node/commit/059f81e4fd)]
- **test**: update test-set-http-max-http-headers to use node:test
(Colin Ihrig)
[#&#8203;56439](https://redirect.github.com/nodejs/node/pull/56439)
-
\[[`ec2940b418`](https://redirect.github.com/nodejs/node/commit/ec2940b418)]
- **test**: update test-child-process-windows-hide to use node:test
(Colin Ihrig)
[#&#8203;56437](https://redirect.github.com/nodejs/node/pull/56437)
-
\[[`0362924880`](https://redirect.github.com/nodejs/node/commit/0362924880)]
- **test**: use unusual chars in the path to ensure our tests are robust
(Antoine du Hamel)
[#&#8203;48409](https://redirect.github.com/nodejs/node/pull/48409)
-
\[[`b6c3869910`](https://redirect.github.com/nodejs/node/commit/b6c3869910)]
- **test**: improve abort signal dropping test (Edy Silva)
[#&#8203;56339](https://redirect.github.com/nodejs/node/pull/56339)
-
\[[`cc648ef923`](https://redirect.github.com/nodejs/node/commit/cc648ef923)]
- **test**: enable ts test on win arm64 (Marco Ippolito)
[#&#8203;56349](https://redirect.github.com/nodejs/node/pull/56349)
-
\[[`68819b4997`](https://redirect.github.com/nodejs/node/commit/68819b4997)]
- **test**: deflake test-watch-file-shared-dependency (Luigi Pinca)
[#&#8203;56344](https://redirect.github.com/nodejs/node/pull/56344)
-
\[[`ca6ed2190c`](https://redirect.github.com/nodejs/node/commit/ca6ed2190c)]
- **test**: skip `test-sqlite-extensions` when SQLite is not built by us
(Antoine du Hamel)
[#&#8203;56341](https://redirect.github.com/nodejs/node/pull/56341)
-
\[[`8ffeb8b58c`](https://redirect.github.com/nodejs/node/commit/8ffeb8b58c)]
- **test**: increase spin for eventloop test on s390 (Michael Dawson)
[#&#8203;56228](https://redirect.github.com/nodejs/node/pull/56228)
-
\[[`6ae9950f08`](https://redirect.github.com/nodejs/node/commit/6ae9950f08)]
- **test**: migrate message eval tests from Python to JS (Yiyun Lei)
[#&#8203;50482](https://redirect.github.com/nodejs/node/pull/50482)
-
\[[`4352bf69e9`](https://redirect.github.com/nodejs/node/commit/4352bf69e9)]
- **test**: check typescript loader (Marco Ippolito)
[#&#8203;54657](https://redirect.github.com/nodejs/node/pull/54657)
-
\[[`406e7db9c3`](https://redirect.github.com/nodejs/node/commit/406e7db9c3)]
- **test**: remove async-hooks/test-writewrap flaky designation (Luigi
Pinca)
[#&#8203;56048](https://redirect.github.com/nodejs/node/pull/56048)
-
\[[`fa56ab2bba`](https://redirect.github.com/nodejs/node/commit/fa56ab2bba)]
- **test**: deflake test-esm-loader-hooks-inspect-brk (Luigi Pinca)
[#&#8203;56050](https://redirect.github.com/nodejs/node/pull/56050)
-
\[[`8e149aac99`](https://redirect.github.com/nodejs/node/commit/8e149aac99)]
- **test**: add test case for listeners (origranot)
[#&#8203;56282](https://redirect.github.com/nodejs/node/pull/56282)
-
\[[`a3f5ef22cd`](https://redirect.github.com/nodejs/node/commit/a3f5ef22cd)]
- **test**: make `test-permission-sqlite-load-extension` more robust
(Antoine du Hamel)
[#&#8203;56295](https://redirect.github.com/nodejs/node/pull/56295)
-
\[[`8cbb7cc838`](https://redirect.github.com/nodejs/node/commit/8cbb7cc838)]
- **test_runner**: print failing assertion only once with spec reporter
(Pietro Marchini)
[#&#8203;56662](https://redirect.github.com/nodejs/node/pull/56662)
-
\[[`1f426bad9a`](https://redirect.github.com/nodejs/node/commit/1f426bad9a)]
- **test_runner**: remove unused errors (Pietro Marchini)
[#&#8203;56607](https://redirect.github.com/nodejs/node/pull/56607)
-
\[[`697a851fb3`](https://redirect.github.com/nodejs/node/commit/697a851fb3)]
- **(SEMVER-MINOR)** **test_runner**: add
TestContext.prototype.waitFor() (Colin Ihrig)
[#&#8203;56595](https://redirect.github.com/nodejs/node/pull/56595)
-
\[[`047537b48c`](https://redirect.github.com/nodejs/node/commit/047537b48c)]
- **(SEMVER-MINOR)** **test_runner**: add t.assert.fileSnapshot() (Colin
Ihrig)
[#&#8203;56459](https://redirect.github.com/nodejs/node/pull/56459)
-
\[[`19b4aa4b14`](https://redirect.github.com/nodejs/node/commit/19b4aa4b14)]
- **test_runner**: run single test file benchmark (Pietro Marchini)
[#&#8203;56479](https://redirect.github.com/nodejs/node/pull/56479)
-
\[[`926cf84e95`](https://redirect.github.com/nodejs/node/commit/926cf84e95)]
- **(SEMVER-MINOR)** **test_runner**: add assert.register() API (Colin
Ihrig)
[#&#8203;56434](https://redirect.github.com/nodejs/node/pull/56434)
-
\[[`fb4661a4cf`](https://redirect.github.com/nodejs/node/commit/fb4661a4cf)]
- **test_runner**: finish marking snapshot testing as stable (Colin
Ihrig)
[#&#8203;56425](https://redirect.github.com/nodejs/node/pull/56425)
-
\[[`900c6c3940`](https://redirect.github.com/nodejs/node/commit/900c6c3940)]
- **tls**: fix error stack conversion in cryptoErrorListToException()
(Joyee Cheung)
[#&#8203;56554](https://redirect.github.com/nodejs/node/pull/56554)
-
\[[`e9f185b658`](https://redirect.github.com/nodejs/node/commit/e9f185b658)]
- **tools**: update doc to new version (Node.js GitHub Bot)
[#&#8203;56259](https://redirect.github.com/nodejs/node/pull/56259)
-
\[[`7644c7e619`](https://redirect.github.com/nodejs/node/commit/7644c7e619)]
- **tools**: update inspector_protocol roller (Chengzhong Wu)
[#&#8203;56649](https://redirect.github.com/nodejs/node/pull/56649)
-
\[[`362272b0a4`](https://redirect.github.com/nodejs/node/commit/362272b0a4)]
- **tools**: do not throw on missing `create-release-proposal.sh`
(Antoine du Hamel)
[#&#8203;56704](https://redirect.github.com/nodejs/node/pull/56704)
-
\[[`df8b835953`](https://redirect.github.com/nodejs/node/commit/df8b835953)]
- **tools**: fix tools-deps-update (Daniel Lemire)
[#&#8203;56684](https://redirect.github.com/nodejs/node/pull/56684)
-
\[[`feba5d3274`](https://redirect.github.com/nodejs/node/commit/feba5d3274)]
- **tools**: do not throw on missing `create-release-proposal.sh`
(Antoine du Hamel)
[#&#8203;56695](https://redirect.github.com/nodejs/node/pull/56695)
-
\[[`9827f7d395`](https://redirect.github.com/nodejs/node/commit/9827f7d395)]
- **tools**: fix permissions in `lint-release-proposal` workflow
(Antoine du Hamel)
[#&#8203;56614](https://redirect.github.com/nodejs/node/pull/56614)
-
\[[`14c562c0dc`](https://redirect.github.com/nodejs/node/commit/14c562c0dc)]
- **tools**: remove github reporter (Carlos Espa)
[#&#8203;56468](https://redirect.github.com/nodejs/node/pull/56468)
-
\[[`ed1785d0ae`](https://redirect.github.com/nodejs/node/commit/ed1785d0ae)]
- **tools**: edit `create-release-proposal` workflow (Antoine du Hamel)
[#&#8203;56540](https://redirect.github.com/nodejs/node/pull/56540)
-
\[[`294e4c42f5`](https://redirect.github.com/nodejs/node/commit/294e4c42f5)]
- **tools**: validate commit list as part of `lint-release-commit`
(Antoine du Hamel)
[#&#8203;56291](https://redirect.github.com/nodejs/node/pull/56291)
-
\[[`98d3474267`](https://redirect.github.com/nodejs/node/commit/98d3474267)]
- **tools**: fix loong64 build failed (Xiao-Tao)
[#&#8203;56466](https://redirect.github.com/nodejs/node/pull/56466)
-
\[[`3e729ceec8`](https://redirect.github.com/nodejs/node/commit/3e729ceec8)]
- **tools**: disable unneeded rule ignoring in Python linting (Rich
Trott)
[#&#8203;56429](https://redirect.github.com/nodejs/node/pull/56429)
-
\[[`d5c05328e2`](https://redirect.github.com/nodejs/node/commit/d5c05328e2)]
- **tools**: use a configurable value for number of open dependabot PRs
(Antoine du Hamel)
[#&#8203;56427](https://redirect.github.com/nodejs/node/pull/56427)
-
\[[`1705cbe002`](https://redirect.github.com/nodejs/node/commit/1705cbe002)]
- **tools**: bump the eslint group in /tools/eslint with 4 updates
(dependabot\[bot])
[#&#8203;56426](https://redirect.github.com/nodejs/node/pull/56426)
-
\[[`53b29b0469`](https://redirect.github.com/nodejs/node/commit/53b29b0469)]
- **tools**: fix `require-common-first` lint rule from subfolder
(Antoine du Hamel)
[#&#8203;56325](https://redirect.github.com/nodejs/node/pull/56325)
-
\[[`105c4ed4fb`](https://redirect.github.com/nodejs/node/commit/105c4ed4fb)]
- **tools**: add release line label when opening release proposal
(Antoine du Hamel)
[#&#8203;56317](https://redirect.github.com/nodejs/node/pull/56317)
-
\[[`30f61f4aa5`](https://redirect.github.com/nodejs/node/commit/30f61f4aa5)]
- **url**: use resolved path to convert UNC paths to URL (Antoine du
Hamel)
[#&#8203;56302](https://redirect.github.com/nodejs/node/pull/56302)
-
\[[`a0aef4dfb6`](https://redirect.github.com/nodejs/node/commit/a0aef4dfb6)]
- **util**: inspect: do not crash on an Error stack that contains a
Symbol (Jordan Harband)
[#&#8203;56573](https://redirect.github.com/nodejs/node/pull/56573)
-
\[[`a8a060341f`](https://redirect.github.com/nodejs/node/commit/a8a060341f)]
- **util**: inspect: do not crash on an Error with a regex `name`
(Jordan Harband)
[#&#8203;56574](https://redirect.github.com/nodejs/node/pull/56574)
-
\[[`ea66bf3553`](https://redirect.github.com/nodejs/node/commit/ea66bf3553)]
- **util**: rename CallSite.column to columnNumber (Chengzhong Wu)
[#&#8203;56584](https://redirect.github.com/nodejs/node/pull/56584)
-
\[[`9cdc3b373c`](https://redirect.github.com/nodejs/node/commit/9cdc3b373c)]
- **util**: do not crash on inspecting function with `Symbol` name
(Jordan Harband)
[#&#8203;56572](https://redirect.github.com/nodejs/node/pull/56572)
-
\[[`0bfbb68569`](https://redirect.github.com/nodejs/node/commit/0bfbb68569)]
- **util**: expose CallSite.scriptId (Chengzhong Wu)
[#&#8203;56551](https://redirect.github.com/nodejs/node/pull/56551)
-
\[[`5dd7116e09`](https://redirect.github.com/nodejs/node/commit/5dd7116e09)]
- **watch**: reload env file for --env-file-if-exists (Jonas)
[#&#8203;56643](https://redirect.github.com/nodejs/node/pull/56643)
-
\[[`c658a8afdf`](https://redirect.github.com/nodejs/node/commit/c658a8afdf)]
- **(SEMVER-MINOR)** **worker**: add eval ts input (Marco Ippolito)
[#&#8203;56394](https://redirect.github.com/nodejs/node/pull/56394)
-
\[[`2e5d038f48`](https://redirect.github.com/nodejs/node/commit/2e5d038f48)]
- **worker**: refactor stdio to improve performance (Matteo Collina)
[#&#8203;56630](https://redirect.github.com/nodejs/node/pull/56630)
-
\[[`f959805d01`](https://redirect.github.com/nodejs/node/commit/f959805d01)]
- **worker**: flush stdout and stderr on exit (Matteo Collina)
[#&#8203;56428](https://redirect.github.com/nodejs/node/pull/56428)

###
[`v22.13.1`](https://redirect.github.com/nodejs/node/releases/tag/v22.13.1):
2025-01-21, Version 22.13.1 &#x27;Jod&#x27; (LTS), @&#8203;RafaelGSS

[Compare
Source](https://redirect.github.com/nodejs/node/compare/v22.13.0...v22.13.1)

This is a security release.

##### Notable Changes

- CVE-2025-23083 - src,loader,permission: throw on InternalWorker use
when permission model is enabled (High)
- CVE-2025-23085 - src: fix HTTP2 mem leak on premature close and
ERR_PROTO (Medium)
- CVE-2025-23084 - path: fix path traversal in normalize() on Windows
(Medium)

Dependency update:

- CVE-2025-22150 - Use of Insufficiently Random Values in undici fetch()
(Medium)

##### Commits

-
\[[`520da342e0`](https://redirect.github.com/nodejs/node/commit/520da342e0)]
- **(CVE-2025-22150)** **deps**: update undici to v6.21.1 (Matteo
Collina)
[nodejs-private/node-private#662](https://redirect.github.com/nodejs-private/node-private/pull/662)
-
\[[`99f217369f`](https://redirect.github.com/nodejs/node/commit/99f217369f)]
- **(CVE-2025-23084)** **path**: fix path traversal in normalize() on
Windows (Tobias Nießen)
[nodejs-private/node-private#555](https://redirect.github.com/nodejs-private/node-private/pull/555)
-
\[[`984f735e35`](https://redirect.github.com/nodejs/node/commit/984f735e35)]
- **(CVE-2025-23085)** **src**: fix HTTP2 mem leak on premature close
and ERR_PROTO (RafaelGSS)
[nodejs-private/node-private#650](https://redirect.github.com/nodejs-private/node-private/pull/650)
-
\[[`2446870618`](https://redirect.github.com/nodejs/node/commit/2446870618)]
- **(CVE-2025-23083)** **src,loader,permission**: throw on
InternalWorker use (RafaelGSS)
[nodejs-private/node-private#651](https://redirect.github.com/nodejs-private/node-private/pull/651)

###
[`v22.13.0`](https://redirect.github.com/nodejs/node/releases/tag/v22.13.0):
2025-01-07, Version 22.13.0 &#x27;Jod&#x27; (LTS), @&#8203;ruyadorno

[Compare
Source](https://redirect.github.com/nodejs/node/compare/v22.12.0...v22.13.0)

##### Notable Changes

##### Stabilize Permission Model

Upgrades the Permission Model status from Active De

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4yNjQuMCIsInVwZGF0ZWRJblZlciI6IjQwLjcuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-09 07:12:55 -04:00
Eli Bosley
4f63b4cf3b feat: native slackware package (#1381)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added detailed versioning for plugin packages incorporating
architecture and build identifiers.
- Simplified and improved install/uninstall scripts with backup and
dynamic package detection.
- Introduced comprehensive setup, verification, patching, and cleanup
scripts for the Unraid API environment.
- Enhanced service control with explicit start, stop, restart, and
status commands.
- Added robust dependency management scripts for restoring and archiving
Node.js modules.
- Implemented vendor archive metadata storage and dynamic handling
during build and runtime.
- Added new CLI options and environment schemas for consistent build
configuration.
- Introduced new shutdown scripts to gracefully stop flash-backup and
unraid-api services.
- Added utility scripts for API version detection and vendor archive
configuration.
- Added a new package description file detailing Unraid API features and
homepage link.

- **Bug Fixes**
- Improved validation and error reporting for missing manifests,
dependencies, and configuration files.
  - Enhanced fallback logic for locating and creating vendor archives.
- Fixed iframe compatibility in UI by updating HTML and Firefox
preference files.

- **Chores**
- Updated .gitignore with generated file patterns for Node.js binaries
and archives.
  - Removed obsolete internal documentation and legacy cleanup scripts.
- Refined Docker Compose and CI workflows to pass precise API versioning
and manage build artifacts.
- Centralized common environment validation and CLI option definitions
across build tools.
- Cleaned up plugin manifest by removing Node.js and PNPM-related
entities and legacy logic.
- Improved logging and error handling in build and installation scripts.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-05-08 22:54:10 -04:00
Michael Datelle
a5f48da322 test: create tests for components batch 3 (#1374)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added comprehensive unit tests for components including SsoButton,
ThemeSwitcher, UpdateOs, UserProfile, WanIpCheck, WelcomeModal,
ActivationModal, ActivationPartnerLogo, ActivationPartnerLogoImg, and
ActivationSteps.
- **Tests**
- Enhanced existing test suites for ColorSwitcher, DummyServerSwitcher,
and I18nHost to improve test isolation, DOM management, and reliability.
- **Style**
- Made minor typographic correction in ActivationModal description text.
- **Refactor**
- Reorganized import statements in several components for improved code
clarity.
- **Chores**
- Added necessary imports in multiple components to support Vue
Composition API features.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: mdatelle <mike@datelle.net>
2025-05-07 16:21:45 -04:00
renovate[bot]
291ee475fb fix(deps): update all non-major dependencies (#1366)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [@manypkg/cli](https://redirect.github.com/Thinkmill/manypkg)
([source](https://redirect.github.com/Thinkmill/manypkg/tree/HEAD/packages/cli))
| [`^0.23.0` ->
`^0.24.0`](https://renovatebot.com/diffs/npm/@manypkg%2fcli/0.23.0/0.24.0)
|
[![age](https://developer.mend.io/api/mc/badges/age/npm/@manypkg%2fcli/0.24.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@manypkg%2fcli/0.24.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@manypkg%2fcli/0.23.0/0.24.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@manypkg%2fcli/0.23.0/0.24.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [lucide-vue-next](https://lucide.dev)
([source](https://redirect.github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-vue-next))
| [`^0.488.0` ->
`^0.506.0`](https://renovatebot.com/diffs/npm/lucide-vue-next/0.488.0/0.506.0)
|
[![age](https://developer.mend.io/api/mc/badges/age/npm/lucide-vue-next/0.506.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/lucide-vue-next/0.506.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/lucide-vue-next/0.488.0/0.506.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/lucide-vue-next/0.488.0/0.506.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [pnpm](https://pnpm.io)
([source](https://redirect.github.com/pnpm/pnpm/tree/HEAD/pnpm)) |
[`10.8.1` ->
`10.10.0`](https://renovatebot.com/diffs/npm/pnpm/10.8.1/10.10.0) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/pnpm/10.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/pnpm/10.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/pnpm/10.8.1/10.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/pnpm/10.8.1/10.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>Thinkmill/manypkg (@&#8203;manypkg/cli)</summary>

###
[`v0.24.0`](https://redirect.github.com/Thinkmill/manypkg/blob/HEAD/packages/cli/CHANGELOG.md#0240)

[Compare
Source](https://redirect.github.com/Thinkmill/manypkg/compare/@manypkg/cli@0.23.0...@manypkg/cli@0.24.0)

##### Minor Changes

- [#&#8203;248](https://redirect.github.com/Thinkmill/manypkg/pull/248)
[`456ca21`](456ca211db)
Thanks [@&#8203;bluwy](https://redirect.github.com/bluwy)! - Change the
default value of the `defaultBranch` config from `"master"` to `"main"`

- [#&#8203;242](https://redirect.github.com/Thinkmill/manypkg/pull/242)
[`1763058`](1763058f9e)
Thanks [@&#8203;spanishpear](https://redirect.github.com/spanishpear)! -
This package is now published as a [pure ESM
package](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c).

- [#&#8203;245](https://redirect.github.com/Thinkmill/manypkg/pull/245)
[`a00f5f7`](a00f5f7179)
Thanks [@&#8203;Andarist](https://redirect.github.com/Andarist)! - Drop
support for Bolt

- [#&#8203;244](https://redirect.github.com/Thinkmill/manypkg/pull/244)
[`f29df03`](f29df03867)
Thanks [@&#8203;Andarist](https://redirect.github.com/Andarist)! - Add
`"engines"` field for explicit node version support. The supported node
versions are `>=20.0.0`.

##### Patch Changes

- Updated dependencies
\[[`3cf8c4e`](3cf8c4e5d4),
[`1763058`](1763058f9e),
[`a00f5f7`](a00f5f7179),
[`f29df03`](f29df03867)]:
-
[@&#8203;manypkg/get-packages](https://redirect.github.com/manypkg/get-packages)[@&#8203;3](https://redirect.github.com/3).0.0

</details>

<details>
<summary>lucide-icons/lucide (lucide-vue-next)</summary>

###
[`v0.506.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.506.0):
Version 0.506.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.505.0...0.506.0)

##### What's Changed

- perf(react): use implicit return in react package by
[@&#8203;VIKTORVAV99](https://redirect.github.com/VIKTORVAV99) in
[https://github.com/lucide-icons/lucide/pull/2325](https://redirect.github.com/lucide-icons/lucide/pull/2325)
- fix(icons): changed `users` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3143](https://redirect.github.com/lucide-icons/lucide/pull/3143)
- fix(icons): changed `locate-off` icon by
[@&#8203;jamiemlaw](https://redirect.github.com/jamiemlaw) in
[https://github.com/lucide-icons/lucide/pull/3137](https://redirect.github.com/lucide-icons/lucide/pull/3137)
- fix(icons): changed `expand` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/2831](https://redirect.github.com/lucide-icons/lucide/pull/2831)
- feat(icons): Added clock plus icon. by
[@&#8203;gubser](https://redirect.github.com/gubser) in
[https://github.com/lucide-icons/lucide/pull/2996](https://redirect.github.com/lucide-icons/lucide/pull/2996)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.505.0...0.506.0

###
[`v0.505.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.505.0):
Version 0.505.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.504.0...0.505.0)

##### What's Changed

- fix(icons): changed `package-2` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3174](https://redirect.github.com/lucide-icons/lucide/pull/3174)
- docs(icon-design-guide): point people to lucide studio instead of svgo
by [@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3152](https://redirect.github.com/lucide-icons/lucide/pull/3152)
- fix(lucide-svelte): Resolve Svelte 5 deprecation of svelte:component
by [@&#8203;shamaamahh](https://redirect.github.com/shamaamahh) in
[https://github.com/lucide-icons/lucide/pull/3112](https://redirect.github.com/lucide-icons/lucide/pull/3112)
- feat(icons): added `brush-cleaning` icon by
[@&#8203;karsa-mistmere](https://redirect.github.com/karsa-mistmere) in
[https://github.com/lucide-icons/lucide/pull/2395](https://redirect.github.com/lucide-icons/lucide/pull/2395)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.504.0...0.505.0

###
[`v0.504.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.504.0):
Version 0.504.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.503.0...0.504.0)

#### What's Changed

- feat(icons): add door closed locked / unlocked icons by
[@&#8203;lukedukeus](https://redirect.github.com/lukedukeus) in
[https://github.com/lucide-icons/lucide/pull/3060](https://redirect.github.com/lucide-icons/lucide/pull/3060)
- build(dev-deps): Bump dependencies by
[@&#8203;ericfennis](https://redirect.github.com/ericfennis) in
[https://github.com/lucide-icons/lucide/pull/3096](https://redirect.github.com/lucide-icons/lucide/pull/3096)
- fix(icons): redesigned `brush` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3011](https://redirect.github.com/lucide-icons/lucide/pull/3011)
- fix(site): remove studio link from navbar by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3166](https://redirect.github.com/lucide-icons/lucide/pull/3166)
- feat(icons): added `hamburger` icon by
[@&#8203;karsa-mistmere](https://redirect.github.com/karsa-mistmere) in
[https://github.com/lucide-icons/lucide/pull/3165](https://redirect.github.com/lucide-icons/lucide/pull/3165)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.503.0...0.504.0

###
[`v0.503.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.503.0):
Version 0.503.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.502.0...0.503.0)

#### What's Changed

- fix(icons): changed `file-badge-2` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/2933](https://redirect.github.com/lucide-icons/lucide/pull/2933)
- feat(icons): added `wifi-pen` icon by
[@&#8203;luisdlopera](https://redirect.github.com/luisdlopera) in
[https://github.com/lucide-icons/lucide/pull/2576](https://redirect.github.com/lucide-icons/lucide/pull/2576)

#### New Contributors

- [@&#8203;luisdlopera](https://redirect.github.com/luisdlopera) made
their first contribution in
[https://github.com/lucide-icons/lucide/pull/2576](https://redirect.github.com/lucide-icons/lucide/pull/2576)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.502.0...0.503.0

###
[`v0.502.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.502.0):
Version 0.502.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.501.0...0.502.0)

#### What's Changed

- fix(docs): Added link for jguddas next to lucide studio by
[@&#8203;briz123](https://redirect.github.com/briz123) in
[https://github.com/lucide-icons/lucide/pull/3063](https://redirect.github.com/lucide-icons/lucide/pull/3063)
- build(deps-dev): bump vite from 5.4.15 to 5.4.17 by
[@&#8203;dependabot](https://redirect.github.com/dependabot) in
[https://github.com/lucide-icons/lucide/pull/2993](https://redirect.github.com/lucide-icons/lucide/pull/2993)
- fix(build): fix shredder formatting and duplicate contributors error
by [@&#8203;jpjacobpadilla](https://redirect.github.com/jpjacobpadilla)
in
[https://github.com/lucide-icons/lucide/pull/3072](https://redirect.github.com/lucide-icons/lucide/pull/3072)
- fix(icons): rebase non-binary on square-asterisk by
[@&#8203;karsa-mistmere](https://redirect.github.com/karsa-mistmere) in
[https://github.com/lucide-icons/lucide/pull/3071](https://redirect.github.com/lucide-icons/lucide/pull/3071)
- docs(CONTRIBUTING): Grammar fix for CONTRIBUTING by
[@&#8203;ajokt123](https://redirect.github.com/ajokt123) in
[https://github.com/lucide-icons/lucide/pull/3090](https://redirect.github.com/lucide-icons/lucide/pull/3090)
- fix(icons): changed `calendar-plus` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3085](https://redirect.github.com/lucide-icons/lucide/pull/3085)
- fix(icons): changed `book-key` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3062](https://redirect.github.com/lucide-icons/lucide/pull/3062)
- fix(icons): changed `clipboard-paste` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3075](https://redirect.github.com/lucide-icons/lucide/pull/3075)
- fix(icons): changed `orbit` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3074](https://redirect.github.com/lucide-icons/lucide/pull/3074)
- fix(icons): changed `baby` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3073](https://redirect.github.com/lucide-icons/lucide/pull/3073)
- docs(pacakges): Added periods to package summary by
[@&#8203;briz123](https://redirect.github.com/briz123) in
[https://github.com/lucide-icons/lucide/pull/3065](https://redirect.github.com/lucide-icons/lucide/pull/3065)
- fix(docs): PR Conventions by
[@&#8203;briz123](https://redirect.github.com/briz123) in
[https://github.com/lucide-icons/lucide/pull/3066](https://redirect.github.com/lucide-icons/lucide/pull/3066)
- feat(icons): added `ruler-dimension-line` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/2535](https://redirect.github.com/lucide-icons/lucide/pull/2535)

#### New Contributors

- [@&#8203;jpjacobpadilla](https://redirect.github.com/jpjacobpadilla)
made their first contribution in
[https://github.com/lucide-icons/lucide/pull/3072](https://redirect.github.com/lucide-icons/lucide/pull/3072)
- [@&#8203;ajokt123](https://redirect.github.com/ajokt123) made their
first contribution in
[https://github.com/lucide-icons/lucide/pull/3090](https://redirect.github.com/lucide-icons/lucide/pull/3090)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.501.0...0.502.0

###
[`v0.501.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.501.0):
Version 0.501.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.500.0...0.501.0)

##### What's Changed

- feat(angular): export icon data types by
[@&#8203;dzonatan](https://redirect.github.com/dzonatan) in
[https://github.com/lucide-icons/lucide/pull/2820](https://redirect.github.com/lucide-icons/lucide/pull/2820)
- feat: added request-review workflow by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/2502](https://redirect.github.com/lucide-icons/lucide/pull/2502)
- feat(icons): Add columns-3-cog icon by
[@&#8203;irvineacosta](https://redirect.github.com/irvineacosta) in
[https://github.com/lucide-icons/lucide/pull/2763](https://redirect.github.com/lucide-icons/lucide/pull/2763)

##### New Contributors

- [@&#8203;dzonatan](https://redirect.github.com/dzonatan) made their
first contribution in
[https://github.com/lucide-icons/lucide/pull/2820](https://redirect.github.com/lucide-icons/lucide/pull/2820)
- [@&#8203;irvineacosta](https://redirect.github.com/irvineacosta) made
their first contribution in
[https://github.com/lucide-icons/lucide/pull/2763](https://redirect.github.com/lucide-icons/lucide/pull/2763)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.500.0...0.501.0

###
[`v0.500.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.500.0):
Version 0.500.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.499.0...0.500.0)

##### What's Changed

- fix(icons): updated `*-cog` icons by
[@&#8203;UsamaKhan](https://redirect.github.com/UsamaKhan) in
[https://github.com/lucide-icons/lucide/pull/2782](https://redirect.github.com/lucide-icons/lucide/pull/2782)
- fix(icons): arcified `lamp-*` icons by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/2267](https://redirect.github.com/lucide-icons/lucide/pull/2267)
- fix(icons): changed `traffic-cone` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/2941](https://redirect.github.com/lucide-icons/lucide/pull/2941)
- Add `electric-truck` icon by
[@&#8203;LienMaas](https://redirect.github.com/LienMaas) in
[https://github.com/lucide-icons/lucide/pull/1803](https://redirect.github.com/lucide-icons/lucide/pull/1803)
- feat(icons): Add `user-lock` icon by
[@&#8203;anthony-mariotti](https://redirect.github.com/anthony-mariotti)
in
[https://github.com/lucide-icons/lucide/pull/2818](https://redirect.github.com/lucide-icons/lucide/pull/2818)

##### New Contributors

- [@&#8203;UsamaKhan](https://redirect.github.com/UsamaKhan) made their
first contribution in
[https://github.com/lucide-icons/lucide/pull/2782](https://redirect.github.com/lucide-icons/lucide/pull/2782)
- [@&#8203;LienMaas](https://redirect.github.com/LienMaas) made their
first contribution in
[https://github.com/lucide-icons/lucide/pull/1803](https://redirect.github.com/lucide-icons/lucide/pull/1803)
-
[@&#8203;anthony-mariotti](https://redirect.github.com/anthony-mariotti)
made their first contribution in
[https://github.com/lucide-icons/lucide/pull/2818](https://redirect.github.com/lucide-icons/lucide/pull/2818)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.499.0...0.500.0

###
[`v0.499.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.499.0):
Version 0.499.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.498.0...0.499.0)

##### What's Changed

- feat(icons): added `bow-arrow` icon by
[@&#8203;jamiemlaw](https://redirect.github.com/jamiemlaw) in
[https://github.com/lucide-icons/lucide/pull/2418](https://redirect.github.com/lucide-icons/lucide/pull/2418)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.498.0...0.499.0

###
[`v0.498.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.498.0):
Version 0.498.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.497.0...0.498.0)

##### What's Changed

- feat(icons): added `decimals-arrow-left` icon and
`decimals-arrow-right` by
[@&#8203;AnnaSasDev](https://redirect.github.com/AnnaSasDev) in
[https://github.com/lucide-icons/lucide/pull/2945](https://redirect.github.com/lucide-icons/lucide/pull/2945)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.497.0...0.498.0

###
[`v0.497.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.497.0):
Version 0.497.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.496.0...0.497.0)

#### What's Changed

- feat(icons): added `shredder` icon by
[@&#8203;alirashidy](https://redirect.github.com/alirashidy) in
[https://github.com/lucide-icons/lucide/pull/3052](https://redirect.github.com/lucide-icons/lucide/pull/3052)

#### New Contributors

- [@&#8203;alirashidy](https://redirect.github.com/alirashidy) made
their first contribution in
[https://github.com/lucide-icons/lucide/pull/3052](https://redirect.github.com/lucide-icons/lucide/pull/3052)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.496.0...0.497.0

###
[`v0.496.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.496.0):
Version 0.496.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.495.0...0.496.0)

##### What's Changed

- feat(icons): added `squares-*` operation icons by
[@&#8203;EthanHazel](https://redirect.github.com/EthanHazel) in
[https://github.com/lucide-icons/lucide/pull/2585](https://redirect.github.com/lucide-icons/lucide/pull/2585)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.495.0...0.496.0

###
[`v0.495.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.495.0):
Version 0.495.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.494.0...0.495.0)

##### What's Changed

- feat(icons): added `rectangle-goggles` icon by
[@&#8203;EthanHazel](https://redirect.github.com/EthanHazel) in
[https://github.com/lucide-icons/lucide/pull/2515](https://redirect.github.com/lucide-icons/lucide/pull/2515)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.494.0...0.495.0

###
[`v0.494.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.494.0):
Version 0.494.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.493.0...0.494.0)

##### What's Changed

- fix(icons): changed `cpu` icon by
[@&#8203;karsa-mistmere](https://redirect.github.com/karsa-mistmere) in
[https://github.com/lucide-icons/lucide/pull/3033](https://redirect.github.com/lucide-icons/lucide/pull/3033)
- feat(icons): added map-pin-edit icon
[#&#8203;2874](https://redirect.github.com/lucide-icons/lucide/issues/2874)
by [@&#8203;sachinkr7368](https://redirect.github.com/sachinkr7368) in
[https://github.com/lucide-icons/lucide/pull/2957](https://redirect.github.com/lucide-icons/lucide/pull/2957)

##### New Contributors

- [@&#8203;sachinkr7368](https://redirect.github.com/sachinkr7368) made
their first contribution in
[https://github.com/lucide-icons/lucide/pull/2957](https://redirect.github.com/lucide-icons/lucide/pull/2957)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.493.0...0.494.0

###
[`v0.493.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.493.0):
Version 0.493.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.492.0...0.493.0)

##### What's Changed

- feat(icons): added `bubbles` icon by
[@&#8203;vqh2602](https://redirect.github.com/vqh2602) in
[https://github.com/lucide-icons/lucide/pull/2582](https://redirect.github.com/lucide-icons/lucide/pull/2582)
- docs(studio): Add lucide studio to site navbar by
[@&#8203;ericfennis](https://redirect.github.com/ericfennis) in
[https://github.com/lucide-icons/lucide/pull/3058](https://redirect.github.com/lucide-icons/lucide/pull/3058)
- feat(ci): adds dpi preview for 16, 32 and 48px by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3048](https://redirect.github.com/lucide-icons/lucide/pull/3048)
- fix(icons): changed `palette` icon by
[@&#8203;jamiemlaw](https://redirect.github.com/jamiemlaw) in
[https://github.com/lucide-icons/lucide/pull/3015](https://redirect.github.com/lucide-icons/lucide/pull/3015)
- feat(icons): added `brick-wall-fire` icon by
[@&#8203;karsa-mistmere](https://redirect.github.com/karsa-mistmere) in
[https://github.com/lucide-icons/lucide/pull/3036](https://redirect.github.com/lucide-icons/lucide/pull/3036)

##### New Contributors

- [@&#8203;vqh2602](https://redirect.github.com/vqh2602) made their
first contribution in
[https://github.com/lucide-icons/lucide/pull/2582](https://redirect.github.com/lucide-icons/lucide/pull/2582)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.492.0...0.493.0

###
[`v0.492.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.492.0):
Version 0.492.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.491.0...0.492.0)

#### What's Changed

- fix(icons): changed `pipette` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/2927](https://redirect.github.com/lucide-icons/lucide/pull/2927)
- feat(icons): added `heart-plus` & `heart-minus` icon by
[@&#8203;Ayberkyvs](https://redirect.github.com/Ayberkyvs) in
[https://github.com/lucide-icons/lucide/pull/2842](https://redirect.github.com/lucide-icons/lucide/pull/2842)

#### New Contributors

- [@&#8203;Ayberkyvs](https://redirect.github.com/Ayberkyvs) made their
first contribution in
[https://github.com/lucide-icons/lucide/pull/2842](https://redirect.github.com/lucide-icons/lucide/pull/2842)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.491.0...0.492.0

###
[`v0.491.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.491.0):
Version 0.491.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.490.0...0.491.0)

##### What's Changed

- feat(icons): added `rotate-ccw-key` icon by
[@&#8203;pgbradbury](https://redirect.github.com/pgbradbury) in
[https://github.com/lucide-icons/lucide/pull/2587](https://redirect.github.com/lucide-icons/lucide/pull/2587)

##### New Contributors

- [@&#8203;pgbradbury](https://redirect.github.com/pgbradbury) made
their first contribution in
[https://github.com/lucide-icons/lucide/pull/2587](https://redirect.github.com/lucide-icons/lucide/pull/2587)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.490.0...0.491.0

###
[`v0.490.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.490.0):
Version 0.490.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.489.0...0.490.0)

#### What's Changed

- fix(icons): changed `piggy-bank` icon by
[@&#8203;jamiemlaw](https://redirect.github.com/jamiemlaw) in
[https://github.com/lucide-icons/lucide/pull/3044](https://redirect.github.com/lucide-icons/lucide/pull/3044)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.489.0...0.490.0

###
[`v0.489.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.489.0):
Version 0.489.0

[Compare
Source](https://redirect.github.com/lucide-icons/lucide/compare/0.488.0...0.489.0)

##### What's Changed

- fix(icons): changed `toggle` icons by
[@&#8203;jamiemlaw](https://redirect.github.com/jamiemlaw) in
[https://github.com/lucide-icons/lucide/pull/3049](https://redirect.github.com/lucide-icons/lucide/pull/3049)
- fix(dev): added link for preact in installation by
[@&#8203;briz123](https://redirect.github.com/briz123) in
[https://github.com/lucide-icons/lucide/pull/3025](https://redirect.github.com/lucide-icons/lucide/pull/3025)
- fix(react): added aria-hidden fallback for decorative icons by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/2158](https://redirect.github.com/lucide-icons/lucide/pull/2158)
- fix(icons): added 2px gap between layers of `layers-2` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/2918](https://redirect.github.com/lucide-icons/lucide/pull/2918)
- fix(icons): changed `text-cursor-input` icon by
[@&#8203;jguddas](https://redirect.github.com/jguddas) in
[https://github.com/lucide-icons/lucide/pull/3027](https://redirect.github.com/lucide-icons/lucide/pull/3027)

**Full Changelog**:
https://github.com/lucide-icons/lucide/compare/0.488.0...0.489.0

</details>

<details>
<summary>pnpm/pnpm (pnpm)</summary>

###
[`v10.10.0`](https://redirect.github.com/pnpm/pnpm/blob/HEAD/pnpm/CHANGELOG.md#10100)

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v10.9.0...v10.10.0)

##### Minor Changes

- Allow loading the `preResolution`, `importPackage`, and `fetchers`
hooks from local pnpmfile.

##### Patch Changes

- Fix `cd` command, when `shellEmulator` is `true`
[#&#8203;7838](https://redirect.github.com/pnpm/pnpm/issues/7838).
- Sort keys in `pnpm-workspace.yaml`
[#&#8203;9453](https://redirect.github.com/pnpm/pnpm/pull/9453).
- Pass the `npm_package_json` environment variable to the executed
scripts
[#&#8203;9452](https://redirect.github.com/pnpm/pnpm/issues/9452).
- Fixed a mistake in the description of the `--reporter=silent` option.

###
[`v10.9.0`](https://redirect.github.com/pnpm/pnpm/blob/HEAD/pnpm/CHANGELOG.md#1090)

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v10.8.1...v10.9.0)

##### Minor Changes

- **Added support for installing JSR packages.** You can now install JSR
packages using the following syntax:

        pnpm add jsr:<pkg_name>

    or with a version range:

        pnpm add jsr:<pkg_name>@&#8203;<range>

    For example, running:

        pnpm add jsr:@&#8203;foo/bar

    will add the following entry to your `package.json`:

    ```json
    {
      "dependencies": {
        "@&#8203;foo/bar": "jsr:^0.1.2"
      }
    }
    ```

When publishing, this entry will be transformed into a format compatible
with npm, older versions of Yarn, and previous pnpm versions:

    ```json
    {
      "dependencies": {
        "@&#8203;foo/bar": "npm:@&#8203;jsr/foo__bar@^0.1.2"
      }
    }
    ```

Related issue:
[#&#8203;8941](https://redirect.github.com/pnpm/pnpm/issues/8941).

Note: The `@jsr` scope defaults to <https://npm.jsr.io/> if the
`@jsr:registry` setting is not defined.

- Added a new setting, `dangerouslyAllowAllBuilds`, for automatically
running any scripts of dependencies without the need to approve any
builds. It was already possible to allow all builds by adding this to
`pnpm-workspace.yaml`:

    ```yaml
    neverBuiltDependencies: []
    ```

`dangerouslyAllowAllBuilds` has the same effect but also allows to be
set globally via:

        pnpm config set dangerouslyAllowAllBuilds true

    It can also be set when running a command:

        pnpm install --dangerously-allow-all-builds

##### Patch Changes

- Fix a false negative in `verifyDepsBeforeRun` when `nodeLinker` is
`hoisted` and there is a workspace package without dependencies and
`node_modules` directory
[#&#8203;9424](https://redirect.github.com/pnpm/pnpm/issues/9424).
- Explicitly drop `verifyDepsBeforeRun` support for `nodeLinker: pnp`.
Combining `verifyDepsBeforeRun` and `nodeLinker: pnp` will now print a
warning.

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/unraid/api).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4yNDguNCIsInVwZGF0ZWRJblZlciI6IjM5LjI2NC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-02 12:59:53 -04:00
github-actions[bot]
948580917d chore(main): release 4.8.0 (#1377)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-05-01 14:55:55 -07:00
Eli Bosley
39e83b2aa1 feat: move activation code logic into the API (#1369)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added comprehensive activation code customization service with dynamic
theming, partner branding, and UI updates.
- Introduced new GraphQL types and public queries for activation code,
partner info, and theme data.
- Implemented new web UI stores and components for activation modal,
partner logos, and theme management.
- **Improvements**
- Removed legacy activation code scripts, PHP components, and plugin
references, streamlining activation logic.
- Enhanced configuration and environment support for activation and
theming features.
- Improved error handling, validation, and type safety in activation and
customization modules.
- **Bug Fixes**
- Fixed color code validation and path handling in customization
service.
- **Chores**
  - Added pre-commit linting hooks and related configuration.
  - Cleaned up test and development environment files.
- **Tests**
- Added extensive tests covering activation customization service
initialization, data handling, and file modifications.
  - Removed obsolete tests related to legacy activation code store.
- **Refactor**
- Migrated activation and partner branding logic from legacy scripts and
PHP to TypeScript services and GraphQL resolvers.
- Reorganized store and component architecture for activation-related
features.
- **Style**
- Updated UI components for improved branding, theming, accessibility,
and layout consistency.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Zack Spear <hi@zackspear.com>
2025-05-01 17:40:36 -04:00
Eli Bosley
831050f4e8 fix: 400 error when submitting connect settings 2025-05-01 17:03:19 -04:00
Eli Bosley
7ace6d3076 chore: change hotfix to a plus sign 2025-05-01 13:56:32 -04:00
Zack Spear
1ff3d7285e chore: update eligibility copy (#1376) 2025-05-01 10:30:35 -07:00
Pujit Mehrotra
874a507e60 [WIP] fix: authentication when booting into GUI mode (#1368)
Added detection of GUI mode to conditionally enhance session handling.
2025-04-30 23:31:26 -04:00
Michael Datelle
32c6fe6295 test: create tests for components batch 2 (#1365)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Refactor**
- Improved component tests by integrating Pinia's testing utilities for
more reliable store mocking and state management.
- Updated test setup to streamline plugin usage and remove unnecessary
configuration.
- Enhanced test clarity by relying on store state changes and Vue's
reactivity instead of manual mock updates.
- Simplified test cases by focusing on passed props and standardized
store mocking.
- **Chores**
  - Updated test directory structure for better organization.
  - Added additional test mocks for dependencies.
- **New Features**
- Added comprehensive tests for the ColorSwitcher component, verifying
UI elements and theme store interactions.
- Introduced tests for the DevSettings component, confirming UI
rendering and interaction behavior.
- Added detailed tests for the DowngradeOs component covering store
interactions and conditional UI rendering.
- Added new test suites for DummyServerSwitcher component, ensuring
correct rendering and reactive state updates.
- Added new test suites for HeaderOsVersion component, validating
version badge rendering and error state handling.
- Added new test suite for the I18nHost component, validating
internationalization context provisioning and error handling.
- Added a comprehensive test suite for the Modal component, covering UI
behavior, styling, and event handling.
- Added new test suite for the Registration component, verifying
rendering based on server state.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: mdatelle <mike@datelle.net>
2025-04-29 12:44:31 -04:00
Eli Bosley
586653ccc1 chore: add a prefix scalar instead of prefix plugin (#1361)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Introduced a new `PrefixedID` scalar type for all GraphQL IDs,
ensuring unique identifiers across multiple servers by prefixing IDs
with a server identifier.
- Added detailed documentation for the `PrefixedID` scalar in the API
schema.
- Grouped VM and parity check mutations under dedicated fields for
better organization.
- Added new scalar `Port` and input type `AccessUrlInput` for improved
type safety.

- **Refactor**
- Replaced all usages of standard `ID` or `String` with `PrefixedID` for
IDs in queries, mutations, and models.
- Consolidated ID handling by extending a common `Node` base class
across models, removing redundant `id` declarations.
- Updated GraphQL argument types and resolver signatures to explicitly
use `PrefixedID`.
- Updated GraphQL code generation to map `PrefixedID` to TypeScript
`string`.

- **Bug Fixes**
- Enhanced test assertions to verify API key creation timestamps are
strings.
  - Fixed internal property naming for registration ID.

- **Chores**
- Removed legacy ID prefix Apollo Server plugin in favor of the new
scalar approach.
  - Cleaned up imports and unused fields related to ID handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-04-29 12:22:18 -04:00
740 changed files with 49076 additions and 21215 deletions

View File

@@ -0,0 +1,18 @@
{
"permissions": {
"allow": [
"Bash(rg:*)",
"Bash(find:*)",
"Bash(pnpm codegen:*)",
"Bash(pnpm dev:*)",
"Bash(pnpm build:*)",
"Bash(pnpm test:*)",
"Bash(grep:*)",
"Bash(pnpm type-check:*)",
"Bash(pnpm lint:*)",
"Bash(pnpm --filter ./api lint)",
"Bash(mv:*)"
]
},
"enableAllProjectMcpServers": false
}

View File

@@ -1,6 +1,6 @@
---
description:
globs: api/*
globs: api/**/*,api/*
alwaysApply: false
---
@@ -8,4 +8,6 @@ alwaysApply: false
* always run scripts from api/package.json unless requested
* prefer adding new files to the nest repo located at api/src/unraid-api/ instead of the legacy code
* Test suite is VITEST, do not use jest
* Prefer to not mock simple dependencies
pnpm --filter ./api test
* Prefer to not mock simple dependencies

View File

@@ -0,0 +1,8 @@
---
description:
globs:
alwaysApply: true
---
Never add comments unless they are needed for clarity of function
Be CONCISE, keep replies shorter than a paragraph if at all passible.

View File

@@ -0,0 +1,6 @@
---
description:
globs:
alwaysApply: true
---
Never add comments for obvious things, and avoid commenting when starting and ending code blocks

View File

@@ -0,0 +1,9 @@
---
description:
globs: web/**/*
alwaysApply: false
---
* Always run `pnpm codegen` for GraphQL code generation in the web directory
* GraphQL queries must be placed in `.query.ts` files
* GraphQL mutations must be placed in `.mutation.ts` files
* All GraphQL under `web/` and follow this naming convention

View File

@@ -8,7 +8,7 @@ alwaysApply: false
- This is a Nuxt.js app but we are testing with vitest outside of the Nuxt environment
- Nuxt is currently set to auto import so some vue files may need compute or ref imported
- Use pnpm when running termical commands and stay within the web directory.
- The directory for tests is located under `web/test` when running test just run `pnpm test`
- The directory for tests is located under `web/__test__` when running test just run `pnpm test`
### Setup
- Use `mount` from Vue Test Utils for component testing
@@ -18,6 +18,8 @@ alwaysApply: false
```typescript
import { mount } from '@vue/test-utils';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { createTestingPinia } from '@pinia/testing'
import { useSomeStore } from '@/stores/myStore'
import YourComponent from '~/components/YourComponent.vue';
// Mock dependencies
@@ -33,14 +35,25 @@ describe('YourComponent', () => {
it('renders correctly', () => {
const wrapper = mount(YourComponent, {
global: {
plugins: [createTestingPinia()],
stubs: {
// Stub child components when needed
ChildComponent: true,
},
},
});
const store = useSomeStore() // uses the testing pinia!
// state can be directly manipulated
store.name = 'my new name'
// actions are stubbed by default, meaning they don't execute their code by default.
// See below to customize this behavior.
store.someAction()
expect(store.someAction).toHaveBeenCalledTimes(1)
// Assertions
// Assertions on components
expect(wrapper.text()).toContain('Expected content');
});
});
@@ -51,6 +64,7 @@ describe('YourComponent', () => {
- Verify that the expected elements are rendered
- Test component interactions (clicks, inputs, etc.)
- Check for expected prop handling and event emissions
- Use `createTestingPinia()` for mocking stores in components
### Finding Elements
- Use semantic queries like `find('button')` or `find('[data-test="id"]')` but prefer not to use data test ID's
@@ -84,6 +98,8 @@ describe('YourComponent', () => {
## Store Testing with Pinia
### Basic Setup
- When testing Store files use `createPinia` and `setActivePinia`
```typescript
import { createPinia, setActivePinia } from 'pinia';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

49
.github/codeql/README.md vendored Normal file
View File

@@ -0,0 +1,49 @@
# CodeQL Security Analysis for Unraid API
This directory contains custom CodeQL queries and configurations for security analysis of the Unraid API codebase.
## Overview
The analysis is configured to run:
- On all pushes to the main branch
- On all pull requests
- Weekly via scheduled runs
## Custom Queries
The following custom queries are implemented:
1. **API Authorization Bypass Detection**
Identifies API handlers that may not properly check authorization before performing operations.
2. **GraphQL Injection Detection**
Detects potential injection vulnerabilities in GraphQL queries and operations.
3. **Hardcoded Secrets Detection**
Finds potential hardcoded secrets or credentials in the codebase.
4. **Insecure Cryptographic Implementations**
Identifies usage of weak cryptographic algorithms or insecure random number generation.
5. **Path Traversal Vulnerability Detection**
Detects potential path traversal vulnerabilities in file system operations.
## Configuration
The CodeQL analysis is configured in:
- `.github/workflows/codeql-analysis.yml` - Workflow configuration
- `.github/codeql/codeql-config.yml` - CodeQL engine configuration
## Running Locally
To run these queries locally:
1. Install the CodeQL CLI: https://github.com/github/codeql-cli-binaries/releases
2. Create a CodeQL database:
```
codeql database create <db-name> --language=javascript --source-root=.
```
3. Run a query:
```
codeql query run .github/codeql/custom-queries/javascript/api-auth-bypass.ql --database=<db-name>
```

16
.github/codeql/codeql-config.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
name: "Unraid API CodeQL Configuration"
disable-default-queries: false
queries:
- name: Extended Security Queries
uses: security-extended
- name: Custom Unraid API Queries
uses: ./.github/codeql/custom-queries
query-filters:
- exclude:
problem.severity:
- warning
- recommendation
tags contain: security

View File

@@ -0,0 +1,45 @@
/**
* @name Potential API Authorization Bypass
* @description Functions that process API requests without verifying authorization may lead to security vulnerabilities.
* @kind problem
* @problem.severity error
* @precision medium
* @id js/api-auth-bypass
* @tags security
* external/cwe/cwe-285
*/
import javascript
/**
* Identifies functions that appear to handle API requests
*/
predicate isApiHandler(Function f) {
exists(f.getAParameter()) and
(
f.getName().regexpMatch("(?i).*(api|handler|controller|resolver|endpoint).*") or
exists(CallExpr call |
call.getCalleeName().regexpMatch("(?i).*(get|post|put|delete|patch).*") and
call.getArgument(1) = f
)
)
}
/**
* Identifies expressions that appear to perform authorization checks
*/
predicate isAuthCheck(DataFlow::Node node) {
exists(CallExpr call |
call.getCalleeName().regexpMatch("(?i).*(authorize|authenticate|isAuth|checkAuth|verifyAuth|hasPermission|isAdmin|canAccess).*") and
call.flow().getASuccessor*() = node
)
}
from Function apiHandler
where
isApiHandler(apiHandler) and
not exists(DataFlow::Node authCheck |
isAuthCheck(authCheck) and
authCheck.getEnclosingExpr().getEnclosingFunction() = apiHandler
)
select apiHandler, "API handler function may not perform proper authorization checks."

View File

@@ -0,0 +1,77 @@
/**
* @name Potential GraphQL Injection
* @description User-controlled input used directly in GraphQL queries may lead to injection vulnerabilities.
* @kind path-problem
* @problem.severity error
* @precision high
* @id js/graphql-injection
* @tags security
* external/cwe/cwe-943
*/
import javascript
import DataFlow::PathGraph
class GraphQLQueryExecution extends DataFlow::CallNode {
GraphQLQueryExecution() {
exists(string name |
name = this.getCalleeName() and
(
name = "execute" or
name = "executeQuery" or
name = "query" or
name.regexpMatch("(?i).*graphql.*query.*")
)
)
}
DataFlow::Node getQuery() {
result = this.getArgument(0)
}
}
class UserControlledInput extends DataFlow::Node {
UserControlledInput() {
exists(DataFlow::ParameterNode param |
param.getName().regexpMatch("(?i).*(query|request|input|args|variables|params).*") and
this = param
)
or
exists(DataFlow::PropRead prop |
prop.getPropertyName().regexpMatch("(?i).*(query|request|input|args|variables|params).*") and
this = prop
)
}
}
/**
* Holds if `node` is a string concatenation.
*/
predicate isStringConcatenation(DataFlow::Node node) {
exists(BinaryExpr concat |
concat.getOperator() = "+" and
concat.flow() = node
)
}
class GraphQLInjectionConfig extends TaintTracking::Configuration {
GraphQLInjectionConfig() { this = "GraphQLInjectionConfig" }
override predicate isSource(DataFlow::Node source) {
source instanceof UserControlledInput
}
override predicate isSink(DataFlow::Node sink) {
exists(GraphQLQueryExecution exec | sink = exec.getQuery())
}
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
// Add any GraphQL-specific taint steps if needed
isStringConcatenation(succ) and
succ.(DataFlow::BinaryExprNode).getAnOperand() = pred
}
}
from GraphQLInjectionConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "GraphQL query may contain user-controlled input from $@.", source.getNode(), "user input"

View File

@@ -0,0 +1,53 @@
/**
* @name Hardcoded Secrets
* @description Hardcoded secrets or credentials in source code can lead to security vulnerabilities.
* @kind problem
* @problem.severity error
* @precision medium
* @id js/hardcoded-secrets
* @tags security
* external/cwe/cwe-798
*/
import javascript
/**
* Identifies variable declarations or assignments that may contain secrets
*/
predicate isSensitiveAssignment(DataFlow::Node node) {
exists(DataFlow::PropWrite propWrite |
propWrite.getPropertyName().regexpMatch("(?i).*(secret|key|password|token|credential|auth).*") and
propWrite.getRhs() = node
)
or
exists(VariableDeclarator decl |
decl.getName().regexpMatch("(?i).*(secret|key|password|token|credential|auth).*") and
decl.getInit().flow() = node
)
}
/**
* Identifies literals that look like secrets
*/
predicate isSecretLiteral(StringLiteral literal) {
// Match alphanumeric strings of moderate length that may be secrets
literal.getValue().regexpMatch("[A-Za-z0-9_\\-]{8,}") and
not (
// Skip likely non-sensitive literals
literal.getValue().regexpMatch("(?i)^(true|false|null|undefined|localhost|development|production|staging)$") or
// Skip URLs without credentials
literal.getValue().regexpMatch("^https?://[^:@/]+")
)
}
from DataFlow::Node source
where
isSensitiveAssignment(source) and
(
exists(StringLiteral literal |
literal.flow() = source and
isSecretLiteral(literal)
)
)
select source, "This assignment may contain a hardcoded secret or credential."

View File

@@ -0,0 +1,90 @@
/**
* @name Insecure Cryptographic Implementation
* @description Usage of weak cryptographic algorithms or improper implementations can lead to security vulnerabilities.
* @kind problem
* @problem.severity error
* @precision high
* @id js/insecure-crypto
* @tags security
* external/cwe/cwe-327
*/
import javascript
/**
* Identifies calls to crypto functions with insecure algorithms
*/
predicate isInsecureCryptoCall(CallExpr call) {
// Node.js crypto module uses
exists(string methodName |
methodName = call.getCalleeName() and
(
// Detect MD5 usage
methodName.regexpMatch("(?i).*md5.*") or
methodName.regexpMatch("(?i).*sha1.*") or
// Insecure crypto constructors
(
methodName = "createHash" or
methodName = "createCipheriv" or
methodName = "createDecipher"
) and
(
exists(StringLiteral algo |
algo = call.getArgument(0) and
(
algo.getValue().regexpMatch("(?i).*(md5|md4|md2|sha1|des|rc4|blowfish).*") or
algo.getValue().regexpMatch("(?i).*(ecb).*") // ECB mode
)
)
)
)
)
or
// Browser crypto API uses
exists(MethodCallExpr mce, string propertyName |
propertyName = mce.getMethodName() and
(
propertyName = "subtle" and
exists(MethodCallExpr subtleCall |
subtleCall.getReceiver() = mce and
subtleCall.getMethodName() = "encrypt" and
exists(ObjectExpr obj |
obj = subtleCall.getArgument(0) and
exists(Property p |
p = obj.getAProperty() and
p.getName() = "name" and
exists(StringLiteral algo |
algo = p.getInit() and
algo.getValue().regexpMatch("(?i).*(rc4|des|aes-cbc).*")
)
)
)
)
)
)
}
/**
* Identifies usage of Math.random() for security-sensitive operations
*/
predicate isInsecureRandomCall(CallExpr call) {
exists(PropertyAccess prop |
prop.getPropertyName() = "random" and
prop.getBase().toString() = "Math" and
call.getCallee() = prop
)
}
from Expr insecureExpr, string message
where
(
insecureExpr instanceof CallExpr and
isInsecureCryptoCall(insecureExpr) and
message = "Using potentially insecure cryptographic algorithm or mode."
) or (
insecureExpr instanceof CallExpr and
isInsecureRandomCall(insecureExpr) and
message = "Using Math.random() for security-sensitive operation. Consider using crypto.getRandomValues() instead."
)
select insecureExpr, message

View File

@@ -0,0 +1,130 @@
/**
* @name Path Traversal Vulnerability
* @description User-controlled inputs used in file operations may allow for path traversal attacks.
* @kind path-problem
* @problem.severity error
* @precision high
* @id js/path-traversal
* @tags security
* external/cwe/cwe-22
*/
import javascript
import DataFlow::PathGraph
/**
* Identifies sources of user-controlled input
*/
class UserInput extends DataFlow::Node {
UserInput() {
// HTTP request parameters
exists(DataFlow::ParameterNode param |
param.getName().regexpMatch("(?i).*(req|request|param|query|body|user|input).*") and
this = param
)
or
// Access to common request properties
exists(DataFlow::PropRead prop |
(
prop.getPropertyName() = "query" or
prop.getPropertyName() = "body" or
prop.getPropertyName() = "params" or
prop.getPropertyName() = "files"
) and
this = prop
)
}
}
/**
* Identifies fs module imports
*/
class FileSystemAccess extends DataFlow::CallNode {
FileSystemAccess() {
// Node.js fs module functions
exists(string name |
name = this.getCalleeName() and
(
name = "readFile" or
name = "readFileSync" or
name = "writeFile" or
name = "writeFileSync" or
name = "appendFile" or
name = "appendFileSync" or
name = "createReadStream" or
name = "createWriteStream" or
name = "openSync" or
name = "open"
)
)
or
// File system operations via require('fs')
exists(DataFlow::SourceNode fsModule, string methodName |
(fsModule.getAPropertyRead("promises") or fsModule).flowsTo(this.getReceiver()) and
methodName = this.getMethodName() and
(
methodName = "readFile" or
methodName = "writeFile" or
methodName = "appendFile" or
methodName = "readdir" or
methodName = "stat"
)
)
}
DataFlow::Node getPathArgument() {
result = this.getArgument(0)
}
}
/**
* Identifies sanitization of file paths
*/
predicate isPathSanitized(DataFlow::Node node) {
// Check for path normalization or validation
exists(DataFlow::CallNode call |
(
call.getCalleeName() = "resolve" or
call.getCalleeName() = "normalize" or
call.getCalleeName() = "isAbsolute" or
call.getCalleeName() = "relative" or
call.getCalleeName().regexpMatch("(?i).*(sanitize|validate|check).*path.*")
) and
call.flowsTo(node)
)
or
// Check for path traversal mitigation patterns
exists(DataFlow::CallNode call |
call.getCalleeName() = "replace" and
exists(StringLiteral regex |
regex = call.getArgument(0).(DataFlow::RegExpCreationNode).getSource().getAChildExpr() and
regex.getValue().regexpMatch("(\\.\\./|\\.\\.\\\\)")
) and
call.flowsTo(node)
)
}
/**
* Configuration for tracking flow from user input to file system operations
*/
class PathTraversalConfig extends TaintTracking::Configuration {
PathTraversalConfig() { this = "PathTraversalConfig" }
override predicate isSource(DataFlow::Node source) {
source instanceof UserInput
}
override predicate isSink(DataFlow::Node sink) {
exists(FileSystemAccess fileAccess |
sink = fileAccess.getPathArgument()
)
}
override predicate isSanitizer(DataFlow::Node node) {
isPathSanitized(node)
}
}
from PathTraversalConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "File system operation depends on a user-controlled value $@.", source.getNode(), "user input"

View File

@@ -23,6 +23,10 @@ on:
type: string
required: true
description: "Base URL for the plugin builds"
BUILD_NUMBER:
type: string
required: true
description: "Build number for the plugin builds"
secrets:
CF_ACCESS_KEY_ID:
required: true
@@ -100,11 +104,6 @@ jobs:
with:
name: unraid-api
path: ${{ github.workspace }}/plugin/api/
- name: Download PNPM Store
uses: actions/download-artifact@v4
with:
name: packed-node-modules
path: ${{ github.workspace }}/plugin/
- name: Extract Unraid API
run: |
mkdir -p ${{ github.workspace }}/plugin/source/dynamix.unraid.net/usr/local/unraid-api
@@ -113,9 +112,8 @@ jobs:
id: build-plugin
run: |
cd ${{ github.workspace }}/plugin
ls -al
pnpm run build:txz
pnpm run build:plugin --tag="${{ inputs.TAG }}" --base-url="${{ inputs.BASE_URL }}"
pnpm run build:txz --tag="${{ inputs.TAG }}" --base-url="${{ inputs.BASE_URL }}" --api-version="${{ steps.vars.outputs.API_VERSION }}" --build-number="${{ inputs.BUILD_NUMBER }}"
pnpm run build:plugin --tag="${{ inputs.TAG }}" --base-url="${{ inputs.BASE_URL }}" --api-version="${{ steps.vars.outputs.API_VERSION }}" --build-number="${{ inputs.BUILD_NUMBER }}"
- name: Ensure Plugin Files Exist
run: |
@@ -130,11 +128,6 @@ jobs:
exit 1
fi
if [ ! -f ./deploy/*.tar.xz ]; then
echo "Error: .tar.xz file not found in plugin/deploy/"
exit 1
fi
- name: Upload to GHA
uses: actions/upload-artifact@v4
with:

40
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@@ -0,0 +1,40 @@
name: "CodeQL Security Analysis"
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
schedule:
- cron: '0 0 * * 0' # Run weekly on Sundays
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript', 'typescript' ]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
config-file: ./.github/codeql/codeql-config.yml
queries: +security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3

76
.github/workflows/deploy-storybook.yml vendored Normal file
View File

@@ -0,0 +1,76 @@
name: Deploy Storybook to Cloudflare Workers
permissions:
contents: read
pull-requests: write
issues: write
on:
push:
branches:
- main
paths:
- 'unraid-ui/**'
pull_request:
paths:
- 'unraid-ui/**'
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
name: Deploy Storybook
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
- name: Cache APT Packages
uses: awalsh128/cache-apt-pkgs-action@v1.5.1
with:
packages: bash procps python3 libvirt-dev jq zstd git build-essential libvirt-daemon-system
version: 1.0
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Storybook
run: |
cd unraid-ui
pnpm build-storybook
- name: Deploy to Cloudflare Workers (Staging)
id: deploy_staging
if: github.event_name == 'pull_request'
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_DEPLOY_TOKEN }}
command: deploy --env staging
workingDirectory: unraid-ui
- name: Deploy to Cloudflare Workers (Production)
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_DEPLOY_TOKEN }}
command: deploy
workingDirectory: unraid-ui
- name: Comment PR with deployment URL
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `🚀 Storybook has been deployed to staging: ${{ steps.deploy_staging.outputs['deployment-url'] }}`
})

View File

@@ -45,7 +45,7 @@ jobs:
node-version-file: ".nvmrc"
- name: Cache APT Packages
uses: awalsh128/cache-apt-pkgs-action@v1.4.3
uses: awalsh128/cache-apt-pkgs-action@v1.5.1
with:
packages: bash procps python3 libvirt-dev jq zstd git build-essential libvirt-daemon-system
version: 1.0
@@ -72,6 +72,12 @@ jobs:
- name: PNPM Install
run: pnpm install --frozen-lockfile
- name: Lint
run: pnpm run lint
- name: Type Check
run: pnpm run type-check
- name: Setup libvirt
run: |
# Create required groups (if they don't already exist)
@@ -94,7 +100,7 @@ jobs:
auth_unix_rw = "none"
EOF
# Add the current user to libvirt and kvm groups (note: this change wont apply to the current session)
# Add the current user to libvirt and kvm groups (note: this change won't apply to the current session)
sudo usermod -aG libvirt,kvm $USER
sudo mkdir -p /var/run/libvirt
@@ -111,15 +117,47 @@ jobs:
# Verify libvirt is running using sudo to bypass group membership delays
sudo virsh list --all || true
- name: Lint
run: pnpm run lint
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Test
run: pnpm run coverage
- name: Run Tests Concurrently
run: |
set -e
# Run all tests in parallel with labeled output
echo "🚀 Starting API coverage tests..."
pnpm run coverage > api-test.log 2>&1 &
API_PID=$!
echo "🚀 Starting Connect plugin tests..."
(cd ../packages/unraid-api-plugin-connect && pnpm test) > connect-test.log 2>&1 &
CONNECT_PID=$!
echo "🚀 Starting Shared package tests..."
(cd ../packages/unraid-shared && pnpm test) > shared-test.log 2>&1 &
SHARED_PID=$!
# Wait for all processes and capture exit codes
wait $API_PID && echo "✅ API tests completed" || { echo "❌ API tests failed"; API_EXIT=1; }
wait $CONNECT_PID && echo "✅ Connect tests completed" || { echo "❌ Connect tests failed"; CONNECT_EXIT=1; }
wait $SHARED_PID && echo "✅ Shared tests completed" || { echo "❌ Shared tests failed"; SHARED_EXIT=1; }
# Display all outputs
echo "📋 API Test Results:" && cat api-test.log
echo "📋 Connect Plugin Test Results:" && cat connect-test.log
echo "📋 Shared Package Test Results:" && cat shared-test.log
# Exit with error if any test failed
if [[ ${API_EXIT:-0} -eq 1 || ${CONNECT_EXIT:-0} -eq 1 || ${SHARED_EXIT:-0} -eq 1 ]]; then
exit 1
fi
build-api:
name: Build API
runs-on: ubuntu-latest
outputs:
build_number: ${{ steps.buildnumber.outputs.build_number }}
defaults:
run:
working-directory: api
@@ -152,7 +190,7 @@ jobs:
${{ runner.os }}-pnpm-store-
- name: Cache APT Packages
uses: awalsh128/cache-apt-pkgs-action@v1.4.3
uses: awalsh128/cache-apt-pkgs-action@v1.5.1
with:
packages: bash procps python3 libvirt-dev jq zstd git build-essential
version: 1.0
@@ -162,12 +200,6 @@ jobs:
cd ${{ github.workspace }}
pnpm install --frozen-lockfile
- name: Lint
run: pnpm run lint
- name: Type Check
run: pnpm run type-check
- name: Build
run: pnpm run build
@@ -179,11 +211,19 @@ jobs:
PACKAGE_LOCK_VERSION=$(jq -r '.version' package.json)
API_VERSION=$([[ -n "$IS_TAGGED" ]] && echo "$PACKAGE_LOCK_VERSION" || echo "${PACKAGE_LOCK_VERSION}+${GIT_SHA}")
export API_VERSION
echo "API_VERSION=${API_VERSION}" >> $GITHUB_ENV
echo "PACKAGE_LOCK_VERSION=${PACKAGE_LOCK_VERSION}" >> $GITHUB_OUTPUT
- name: Generate build number
id: buildnumber
uses: onyxmueller/build-tag-number@v1
with:
token: ${{secrets.github_token}}
prefix: ${{steps.vars.outputs.PACKAGE_LOCK_VERSION}}
- name: Build
run: |
pnpm run build:release
tar -czf deploy/unraid-api.tgz -C deploy/pack/ .
- name: Upload tgz to Github artifacts
@@ -191,11 +231,6 @@ jobs:
with:
name: unraid-api
path: ${{ github.workspace }}/api/deploy/unraid-api.tgz
- name: Upload Node Modules to Github artifacts
uses: actions/upload-artifact@v4
with:
name: packed-node-modules
path: ${{ github.workspace }}/api/deploy/packed-node-modules.tar.xz
build-unraid-ui-webcomponents:
name: Build Unraid UI Library (Webcomponent Version)
@@ -232,7 +267,7 @@ jobs:
${{ runner.os }}-pnpm-store-
- name: Cache APT Packages
uses: awalsh128/cache-apt-pkgs-action@v1.4.3
uses: awalsh128/cache-apt-pkgs-action@v1.5.1
with:
packages: bash procps python3 libvirt-dev jq zstd git build-essential
version: 1.0
@@ -340,6 +375,7 @@ jobs:
TAG: ${{ github.event.pull_request.number && format('PR{0}', github.event.pull_request.number) || '' }}
BUCKET_PATH: ${{ github.event.pull_request.number && format('unraid-api/tag/PR{0}', github.event.pull_request.number) || 'unraid-api' }}
BASE_URL: "https://preview.dl.unraid.net/unraid-api"
BUILD_NUMBER: ${{ needs.build-api.outputs.build_number }}
secrets:
CF_ACCESS_KEY_ID: ${{ secrets.CF_ACCESS_KEY_ID }}
CF_SECRET_ACCESS_KEY: ${{ secrets.CF_SECRET_ACCESS_KEY }}
@@ -362,6 +398,7 @@ jobs:
TAG: ""
BUCKET_PATH: unraid-api
BASE_URL: "https://stable.dl.unraid.net/unraid-api"
BUILD_NUMBER: ${{ needs.build-api.outputs.build_number }}
secrets:
CF_ACCESS_KEY_ID: ${{ secrets.CF_ACCESS_KEY_ID }}
CF_SECRET_ACCESS_KEY: ${{ secrets.CF_SECRET_ACCESS_KEY }}

View File

@@ -4,43 +4,68 @@ on:
pull_request:
types:
- closed
workflow_dispatch:
inputs:
pr_number:
description: "PR number to test with"
required: true
type: string
pr_merged:
description: "Simulate merged PR"
required: true
type: boolean
default: true
jobs:
push-staging:
if: github.event.pull_request.merged == true
if: (github.event_name == 'pull_request' && github.event.pull_request.merged == true) || (github.event_name == 'workflow_dispatch' && inputs.pr_merged == true)
runs-on: ubuntu-latest
permissions:
contents: read
actions: read
steps:
- name: Set Timezone
uses: szenius/set-timezone@v2.0
with:
timezoneLinux: "America/Los_Angeles"
- name: Checkout repo
uses: actions/checkout@v4
with:
ref: refs/pull/${{ github.event.pull_request.base.ref }}/merge
- name: Set PR number
id: pr_number
run: |
if [ "${{ github.event_name }}" == "pull_request" ]; then
echo "pr_number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT
else
echo "pr_number=${{ inputs.pr_number }}" >> $GITHUB_OUTPUT
fi
- name: Download artifact
uses: actions/download-artifact@v4
uses: dawidd6/action-download-artifact@v11
with:
name: connect-files
name_is_regexp: true
name: unraid-plugin-.*
path: connect-files
pr: ${{ steps.pr_number.outputs.pr_number }}
workflow_conclusion: success
workflow_search: true
search_artifacts: true
- name: Update Downloaded Staging Plugin to New Date
run: |
if [ ! -f "connect-files/plugins/dynamix.unraid.net.pr.plg" ]; then
echo "ERROR: dynamix.unraid.net.pr.plg not found"
# Find the .plg file in the downloaded artifact
plgfile=$(find connect-files -name "*.plg" -type f | head -1)
if [ ! -f "$plgfile" ]; then
echo "ERROR: .plg file not found in connect-files/"
ls -la connect-files/
exit 1
fi
plgfile="connect-files/plugins/dynamix.unraid.net.pr.plg"
echo "Found plugin file: $plgfile"
version=$(date +"%Y.%m.%d.%H%M")
sed -i -E "s#(<!ENTITY version \").*(\">)#\1${version}\2#g" "${plgfile}" || exit 1
# Change the plugin url to point to staging
url="https://preview.dl.unraid.net/unraid-api/dynamix.unraid.net.plg"
sed -i -E "s#(<!ENTITY pluginURL \").*(\">)#\1${url}\2#g" "${plgfile}" || exit 1
sed -i -E "s#(<!ENTITY plugin_url \").*?(\">)#\1${url}\2#g" "${plgfile}" || exit 1
cat "${plgfile}"
mkdir -p pr-release
mv "${plgfile}" pr-release/dynamix.unraid.net.plg
@@ -54,4 +79,4 @@ jobs:
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_SECRET_ACCESS_KEY }}
AWS_REGION: "auto"
SOURCE_DIR: pr-release
DEST_DIR: unraid-api/pr/${{ github.event.pull_request.number }}
DEST_DIR: unraid-api/tag/PR${{ steps.pr_number.outputs.pr_number }}

View File

@@ -30,9 +30,11 @@ jobs:
prerelease: false
- uses: actions/setup-node@v4
with:
node-version: '22.x'
node-version: '22.17.0'
- run: |
echo '${{ steps.release-info.outputs.body }}' >> release-notes.txt
cat << 'EOF' > release-notes.txt
${{ steps.release-info.outputs.body }}
EOF
- run: npm install html-escaper@2 xml2js
- name: Update Plugin Changelog
uses: actions/github-script@v7

View File

@@ -28,10 +28,10 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.13"
python-version: "3.13.5"
- name: Cache APT Packages
uses: awalsh128/cache-apt-pkgs-action@v1.4.3
uses: awalsh128/cache-apt-pkgs-action@v1.5.1
with:
packages: libvirt-dev
version: 1.0

2
.gitignore vendored
View File

@@ -108,4 +108,4 @@ web/scripts/.sync-webgui-repo-*
plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/data/activation-data.php
# Config file that changes between versions
api/dev/Unraid.net/myservers.cfg
api/dev/Unraid.net/myservers.cfg

12
.husky/_/pre-commit Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/sh
if [ "$SKIP_SIMPLE_GIT_HOOKS" = "1" ]; then
echo "[INFO] SKIP_SIMPLE_GIT_HOOKS is set to 1, skipping hook."
exit 0
fi
if [ -f "$SIMPLE_GIT_HOOKS_RC" ]; then
. "$SIMPLE_GIT_HOOKS_RC"
fi
pnpm lint-staged

2
.nvmrc
View File

@@ -1 +1 @@
22
22.17.0

1
.rclone-version Normal file
View File

@@ -0,0 +1 @@
1.69.1

View File

@@ -1 +1 @@
{".":"4.7.0"}
{".":"4.9.2"}

27
.vscode/settings.json vendored
View File

@@ -1,15 +1,14 @@
{
"files.associations": {
"*.page": "php"
},
"editor.codeActionsOnSave": {
"source.fixAll": "never",
"source.fixAll.eslint": "explicit"
},
"i18n-ally.localesPaths": [
"locales"
],
"i18n-ally.keystyle": "flat",
"eslint.experimental.useFlatConfig": true
}
"files.associations": {
"*.page": "php"
},
"editor.codeActionsOnSave": {
"source.fixAll": "never",
"source.fixAll.eslint": "explicit"
},
"i18n-ally.localesPaths": ["locales"],
"i18n-ally.keystyle": "flat",
"eslint.experimental.useFlatConfig": true,
"typescript.preferences.importModuleSpecifier": "non-relative",
"javascript.preferences.importModuleSpecifier": "non-relative"
}

137
CLAUDE.md Normal file
View File

@@ -0,0 +1,137 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
This is the Unraid API monorepo containing multiple packages that provide API functionality for Unraid servers. It uses pnpm workspaces with the following structure:
- `/api` - Core NestJS API server with GraphQL
- `/web` - Nuxt.js frontend application
- `/unraid-ui` - Vue 3 component library
- `/plugin` - Unraid plugin package (.plg)
- `/packages` - Shared packages and API plugins
## Essential Commands
### Development
```bash
pnpm install # Install all dependencies
pnpm dev # Run all dev servers concurrently
pnpm build # Build all packages
pnpm build:watch # Watch mode with local plugin build
```
### Testing & Code Quality
```bash
pnpm test # Run all tests
pnpm lint # Run linting
pnpm lint:fix # Fix linting issues
pnpm type-check # TypeScript type checking
```
### API Development
```bash
cd api && pnpm dev # Run API server (http://localhost:3001)
cd api && pnpm test:watch # Run tests in watch mode
cd api && pnpm codegen # Generate GraphQL types
```
### Deployment
```bash
pnpm unraid:deploy <SERVER_IP> # Deploy all to Unraid server
```
## Architecture Notes
### API Structure (NestJS)
- Modules: `auth`, `config`, `plugins`, `emhttp`, `monitoring`
- GraphQL API with Apollo Server at `/graphql`
- Redux store for state management in `src/store/`
- Plugin system for extending functionality
- Entry points: `src/index.ts` (server), `src/cli.ts` (CLI)
### Key Patterns
- TypeScript imports use `.js` extensions (ESM compatibility)
- NestJS dependency injection with decorators
- GraphQL schema-first approach with code generation
- API plugins follow specific structure (see `api/docs/developer/api-plugins.md`)
### Authentication
- API key authentication via headers
- Cookie-based session management
- Keys stored in `/boot/config/plugins/unraid-api/`
### Development Workflow
1. Work Intent required before starting development
2. Fork from `main` branch
3. Reference Work Intent in PR
4. No direct pushes to main
### Debug Mode
```bash
LOG_LEVEL=debug unraid-api start --debug
```
Enables GraphQL playground at `http://tower.local/graphql`
## Coding Guidelines
### General Rules
- Never add comments unless they are needed for clarity of function
- Never add comments for obvious things, and avoid commenting when starting and ending code blocks
- Be CONCISE, keep replies shorter than a paragraph if at all possible
### API Development Rules (`api/**/*`)
- Use pnpm ONLY for package management
- Always run scripts from api/package.json unless requested
- Prefer adding new files to the NestJS repo located at `api/src/unraid-api/` instead of the legacy code
- Test suite is VITEST, do not use jest
- Run tests with: `pnpm --filter ./api test`
- Prefer to not mock simple dependencies
### Web Development Rules (`web/**/*`)
- Always run `pnpm codegen` for GraphQL code generation in the web directory
- GraphQL queries must be placed in `.query.ts` files
- GraphQL mutations must be placed in `.mutation.ts` files
- All GraphQL under `web/` must follow this naming convention
### Testing Guidelines
#### Vue Component Testing
- This is a Nuxt.js app but we are testing with vitest outside of the Nuxt environment
- Nuxt is currently set to auto import so some vue files may need compute or ref imported
- Use pnpm when running terminal commands and stay within the web directory
- Tests are located under `web/__test__`, run with `pnpm test`
- Use `mount` from Vue Test Utils for component testing
- Stub complex child components that aren't the focus of the test
- Mock external dependencies and services
- Test component behavior and output, not implementation details
- Use `createTestingPinia()` for mocking stores in components
- Find elements with semantic queries like `find('button')` rather than data-test IDs
- Use `await nextTick()` for DOM updates
- Always await async operations before making assertions
#### Store Testing with Pinia
- Use `createPinia()` and `setActivePinia` when testing Store files
- Only use `createTestingPinia` if you specifically need its testing features
- Let stores initialize with their natural default state
- Don't mock the store being tested
- Ensure Vue reactivity imports are added to store files (computed, ref, watchEffect)
- Place all mock declarations at the top level
- Use factory functions for module mocks to avoid hoisting issues
- Clear mocks between tests to ensure isolation

View File

@@ -11,6 +11,10 @@ PATHS_KEYFILE_BASE=./dev/Unraid.net # Keyfile location
PATHS_MACHINE_ID=./dev/data/machine-id
PATHS_PARITY_CHECKS=./dev/states/parity-checks.log
PATHS_CONFIG_MODULES=./dev/configs
PATHS_ACTIVATION_BASE=./dev/activation
PATHS_PASSWD=./dev/passwd
PATHS_RCLONE_SOCKET=./dev/rclone-socket
PATHS_LOG_BASE=./dev/log # Where we store logs
ENVIRONMENT="development"
NODE_ENV="development"
PORT="3001"

View File

@@ -11,5 +11,7 @@ PATHS_KEYFILE_BASE=./dev/Unraid.net # Keyfile location
PATHS_MACHINE_ID=./dev/data/machine-id
PATHS_PARITY_CHECKS=./dev/states/parity-checks.log
PATHS_CONFIG_MODULES=./dev/configs
PATHS_ACTIVATION_BASE=./dev/activation
PATHS_PASSWD=./dev/passwd
PORT=5000
NODE_ENV="test"

View File

@@ -3,5 +3,7 @@
"eslint.options": {
"flags": ["unstable_ts_config"],
"overrideConfigFile": ".eslintrc.ts"
}
},
"typescript.preferences.importModuleSpecifier": "non-relative",
"javascript.preferences.importModuleSpecifier": "non-relative"
}

View File

@@ -1,5 +1,121 @@
# Changelog
## [4.9.2](https://github.com/unraid/api/compare/v4.9.1...v4.9.2) (2025-07-09)
### Bug Fixes
* invalid configs no longer crash API ([#1491](https://github.com/unraid/api/issues/1491)) ([6bf3f77](https://github.com/unraid/api/commit/6bf3f776380edeff5133517e6aca223556e30144))
* invalid state for unraid plugin ([#1492](https://github.com/unraid/api/issues/1492)) ([39b8f45](https://github.com/unraid/api/commit/39b8f453da23793ef51f8e7f7196370aada8c5aa))
* release note escaping ([5b6bcb6](https://github.com/unraid/api/commit/5b6bcb6043a5269bff4dc28714d787a5a3f07e22))
## [4.9.1](https://github.com/unraid/api/compare/v4.9.0...v4.9.1) (2025-07-08)
### Bug Fixes
* **HeaderOsVersion:** adjust top margin for header component ([#1485](https://github.com/unraid/api/issues/1485)) ([862b54d](https://github.com/unraid/api/commit/862b54de8cd793606f1d29e76c19d4a0e1ae172f))
* sign out doesn't work ([#1486](https://github.com/unraid/api/issues/1486)) ([f3671c3](https://github.com/unraid/api/commit/f3671c3e0750b79be1f19655a07a0e9932289b3f))
## [4.9.0](https://github.com/unraid/api/compare/v4.8.0...v4.9.0) (2025-07-08)
### Features
* add graphql resource for API plugins ([#1420](https://github.com/unraid/api/issues/1420)) ([642a220](https://github.com/unraid/api/commit/642a220c3a796829505d8449dc774968c9d5c222))
* add management page for API keys ([#1408](https://github.com/unraid/api/issues/1408)) ([0788756](https://github.com/unraid/api/commit/0788756b918a8e99be51f34bf6f96bbe5b67395a))
* add rclone ([#1362](https://github.com/unraid/api/issues/1362)) ([5517e75](https://github.com/unraid/api/commit/5517e7506b05c7bef5012bb9f8d2103e91061997))
* API key management ([#1407](https://github.com/unraid/api/issues/1407)) ([d37dc3b](https://github.com/unraid/api/commit/d37dc3bce28bad1c893ae7eff96ca5ffd9177648))
* api plugin management via CLI ([#1416](https://github.com/unraid/api/issues/1416)) ([3dcbfbe](https://github.com/unraid/api/commit/3dcbfbe48973b8047f0c6c560068808d86ac6970))
* build out docker components ([#1427](https://github.com/unraid/api/issues/1427)) ([711cc9a](https://github.com/unraid/api/commit/711cc9ac926958bcf2996455b023ad265b041530))
* docker and info resolver issues ([#1423](https://github.com/unraid/api/issues/1423)) ([9901039](https://github.com/unraid/api/commit/9901039a3863de06b520e23cb2573b610716c673))
* fix shading in UPC to be less severe ([#1438](https://github.com/unraid/api/issues/1438)) ([b7c2407](https://github.com/unraid/api/commit/b7c240784052276fc60e064bd7d64dd6e801ae90))
* info resolver cleanup ([#1425](https://github.com/unraid/api/issues/1425)) ([1b279bb](https://github.com/unraid/api/commit/1b279bbab3a51e7d032e7e3c9898feac8bfdbafa))
* initial codeql setup ([#1390](https://github.com/unraid/api/issues/1390)) ([2ade7eb](https://github.com/unraid/api/commit/2ade7eb52792ef481aaf711dc07029629ea107d9))
* initialize claude code in codebse ([#1418](https://github.com/unraid/api/issues/1418)) ([b6c4ee6](https://github.com/unraid/api/commit/b6c4ee6eb4b9ebb6d6e59a341e1f51b253578752))
* move api key fetching to use api key service ([#1439](https://github.com/unraid/api/issues/1439)) ([86bea56](https://github.com/unraid/api/commit/86bea5627270a2a18c5b7db36dd59061ab61e753))
* move to cron v4 ([#1428](https://github.com/unraid/api/issues/1428)) ([b8035c2](https://github.com/unraid/api/commit/b8035c207a6e387c7af3346593a872664f6c867b))
* move to iframe for changelog ([#1388](https://github.com/unraid/api/issues/1388)) ([fcd6fbc](https://github.com/unraid/api/commit/fcd6fbcdd48e7f224b3bd8799a668d9e01967f0c))
* native slackware package ([#1381](https://github.com/unraid/api/issues/1381)) ([4f63b4c](https://github.com/unraid/api/commit/4f63b4cf3bb9391785f07a38defe54ec39071caa))
* send active unraid theme to docs ([#1400](https://github.com/unraid/api/issues/1400)) ([f71943b](https://github.com/unraid/api/commit/f71943b62b30119e17766e56534962630f52a591))
* slightly better watch mode ([#1398](https://github.com/unraid/api/issues/1398)) ([881f1e0](https://github.com/unraid/api/commit/881f1e09607d1e4a8606f8d048636ba09d8fcac1))
* upgrade nuxt-custom-elements ([#1461](https://github.com/unraid/api/issues/1461)) ([345e83b](https://github.com/unraid/api/commit/345e83bfb0904381d784fc77b3dcd3ad7e53d898))
* use bigint instead of long ([#1403](https://github.com/unraid/api/issues/1403)) ([574d572](https://github.com/unraid/api/commit/574d572d6567c652057b29776694e86267316ca7))
### Bug Fixes
* activation indicator removed ([5edfd82](https://github.com/unraid/api/commit/5edfd823b862cfc1f864565021f12334fe9317c6))
* alignment of settings on ManagementAccess settings page ([#1421](https://github.com/unraid/api/issues/1421)) ([70c790f](https://github.com/unraid/api/commit/70c790ff89075a785d7f0623bbf3c34a3806bbdc))
* allow rclone to fail to initialize ([#1453](https://github.com/unraid/api/issues/1453)) ([7c6f02a](https://github.com/unraid/api/commit/7c6f02a5cb474fb285db294ec6f80d1c2c57e142))
* always download 7.1 versioned files for patching ([edc0d15](https://github.com/unraid/api/commit/edc0d1578b89c3b3e56e637de07137e069656fa8))
* api `pnpm type-check` ([#1442](https://github.com/unraid/api/issues/1442)) ([3122bdb](https://github.com/unraid/api/commit/3122bdb953eec58469fd9cf6f468e75621781040))
* **api:** connect config `email` validation ([#1454](https://github.com/unraid/api/issues/1454)) ([b9a1b9b](https://github.com/unraid/api/commit/b9a1b9b08746b6d4cb2128d029a3dab7cdd47677))
* backport unraid/webgui[#2269](https://github.com/unraid/api/issues/2269) rc.nginx update ([#1436](https://github.com/unraid/api/issues/1436)) ([a7ef06e](https://github.com/unraid/api/commit/a7ef06ea252545cef084e21cea741a8ec866e7cc))
* bigint ([e54d27a](https://github.com/unraid/api/commit/e54d27aede1b1e784971468777c5e65cde66f2ac))
* config migration from `myservers.cfg` ([#1440](https://github.com/unraid/api/issues/1440)) ([c4c9984](https://github.com/unraid/api/commit/c4c99843c7104414120bffc5dd5ed78ab6c8ba02))
* **connect:** fatal race-condition in websocket disposal ([#1462](https://github.com/unraid/api/issues/1462)) ([0ec0de9](https://github.com/unraid/api/commit/0ec0de982f017b61a145c7a4176718b484834f41))
* **connect:** mothership connection ([#1464](https://github.com/unraid/api/issues/1464)) ([7be8bc8](https://github.com/unraid/api/commit/7be8bc84d3831f9cea7ff62d0964612ad366a976))
* console hidden ([9b85e00](https://github.com/unraid/api/commit/9b85e009b833706294a841a54498e45a8e0204ed))
* debounce is too long ([#1426](https://github.com/unraid/api/issues/1426)) ([f12d231](https://github.com/unraid/api/commit/f12d231e6376d0f253cee67b7ed690c432c63ec5))
* delete legacy connect keys and ensure description ([22fe91c](https://github.com/unraid/api/commit/22fe91cd561e88aa24e8f8cfa5a6143e7644e4e0))
* **deps:** pin dependencies ([#1465](https://github.com/unraid/api/issues/1465)) ([ba75a40](https://github.com/unraid/api/commit/ba75a409a4d3e820308b78fd5a5380021d3757b0))
* **deps:** pin dependencies ([#1470](https://github.com/unraid/api/issues/1470)) ([412b329](https://github.com/unraid/api/commit/412b32996d9c8352c25309cc0d549a57468d0fb5))
* **deps:** storybook v9 ([#1476](https://github.com/unraid/api/issues/1476)) ([45bb49b](https://github.com/unraid/api/commit/45bb49bcd60a9753be492203111e489fd37c1a5f))
* **deps:** update all non-major dependencies ([#1366](https://github.com/unraid/api/issues/1366)) ([291ee47](https://github.com/unraid/api/commit/291ee475fb9ef44f6da7b76a9eb11b7dd29a5d13))
* **deps:** update all non-major dependencies ([#1379](https://github.com/unraid/api/issues/1379)) ([8f70326](https://github.com/unraid/api/commit/8f70326d0fe3e4c3bcd3e8e4e6566766f1c05eb7))
* **deps:** update all non-major dependencies ([#1389](https://github.com/unraid/api/issues/1389)) ([cb43f95](https://github.com/unraid/api/commit/cb43f95233590888a8e20a130e62cadc176c6793))
* **deps:** update all non-major dependencies ([#1399](https://github.com/unraid/api/issues/1399)) ([68df344](https://github.com/unraid/api/commit/68df344a4b412227cffa96867f086177b251f028))
* **deps:** update dependency @types/diff to v8 ([#1393](https://github.com/unraid/api/issues/1393)) ([00da27d](https://github.com/unraid/api/commit/00da27d04f2ee2ca8b8b9cdcc6ea3c490c02a3a4))
* **deps:** update dependency cache-manager to v7 ([#1413](https://github.com/unraid/api/issues/1413)) ([9492c2a](https://github.com/unraid/api/commit/9492c2ae6a0086d14e73d280c55746206b73a7b0))
* **deps:** update dependency commander to v14 ([#1394](https://github.com/unraid/api/issues/1394)) ([106ea09](https://github.com/unraid/api/commit/106ea093996f2d0c71c1511bc009ecc9a6be91ec))
* **deps:** update dependency diff to v8 ([#1386](https://github.com/unraid/api/issues/1386)) ([e580f64](https://github.com/unraid/api/commit/e580f646a52b8bda605132cf44ec58137e08dd42))
* **deps:** update dependency dotenv to v17 ([#1474](https://github.com/unraid/api/issues/1474)) ([d613bfa](https://github.com/unraid/api/commit/d613bfa0410e7ef8451fc8ea20e57a7db67f7994))
* **deps:** update dependency lucide-vue-next to ^0.509.0 ([#1383](https://github.com/unraid/api/issues/1383)) ([469333a](https://github.com/unraid/api/commit/469333acd4a0cbeecc9e9cbadb2884289d83aee3))
* **deps:** update dependency marked to v16 ([#1444](https://github.com/unraid/api/issues/1444)) ([453a5b2](https://github.com/unraid/api/commit/453a5b2c9591f755ce07548a9996d7a6cf0925c4))
* **deps:** update dependency shadcn-vue to v2 ([#1302](https://github.com/unraid/api/issues/1302)) ([26ecf77](https://github.com/unraid/api/commit/26ecf779e675d0bc533d61e045325ab062effcbf))
* **deps:** update dependency vue-sonner to v2 ([#1401](https://github.com/unraid/api/issues/1401)) ([53ca414](https://github.com/unraid/api/commit/53ca41404f13c057c340dcf9010af72c3365e499))
* disable file changes on Unraid 7.2 ([#1382](https://github.com/unraid/api/issues/1382)) ([02de89d](https://github.com/unraid/api/commit/02de89d1309f67e4b6d4f8de5f66815ee4d2464c))
* do not start API with doinst.sh ([7d88b33](https://github.com/unraid/api/commit/7d88b3393cbd8ab1e93a86dfa1b7b74cc97255cc))
* do not uninstall fully on 7.2 ([#1484](https://github.com/unraid/api/issues/1484)) ([2263881](https://github.com/unraid/api/commit/22638811a9fdb524420b1347ac49cfaa51bbecb5))
* drop console with terser ([a87d455](https://github.com/unraid/api/commit/a87d455bace04aab9d7fa0e63cb61d26ef9b3b72))
* error logs from `cloud` query when connect is not installed ([#1450](https://github.com/unraid/api/issues/1450)) ([719f460](https://github.com/unraid/api/commit/719f460016d769255582742d7d71ca97d132022b))
* flash backup integration with Unraid Connect config ([#1448](https://github.com/unraid/api/issues/1448)) ([038c582](https://github.com/unraid/api/commit/038c582aed5f5efaea3583372778b9baa318e1ea))
* header padding regression ([#1477](https://github.com/unraid/api/issues/1477)) ([e791cc6](https://github.com/unraid/api/commit/e791cc680de9c40378043348ddca70902da6d250))
* incorrect state merging in redux store ([#1437](https://github.com/unraid/api/issues/1437)) ([17b7428](https://github.com/unraid/api/commit/17b74287796e6feb75466033e279dc3bcf57f1e6))
* lanip copy button not present ([#1459](https://github.com/unraid/api/issues/1459)) ([a280786](https://github.com/unraid/api/commit/a2807864acef742e454d87bb093ee91806e527e5))
* move to bigint scalar ([b625227](https://github.com/unraid/api/commit/b625227913e80e4731a13b54b525ec7385918c51))
* node_modules dir removed on plugin update ([#1406](https://github.com/unraid/api/issues/1406)) ([7b005cb](https://github.com/unraid/api/commit/7b005cbbf682a1336641f5fc85022e9d651569d0))
* omit Connect actions in UPC when plugin is not installed ([#1417](https://github.com/unraid/api/issues/1417)) ([8c8a527](https://github.com/unraid/api/commit/8c8a5276b49833c08bca133e374e1e66273b41aa))
* parsing of `ssoEnabled` in state.php ([#1455](https://github.com/unraid/api/issues/1455)) ([f542c8e](https://github.com/unraid/api/commit/f542c8e0bd9596d9d3abf75b58b97d95fb033215))
* pin ranges ([#1460](https://github.com/unraid/api/issues/1460)) ([f88400e](https://github.com/unraid/api/commit/f88400eea820ac80c867fdb63cd503ed91493146))
* pr plugin promotion workflow ([#1456](https://github.com/unraid/api/issues/1456)) ([13bd9bb](https://github.com/unraid/api/commit/13bd9bb5670bb96b158068114d62572d88c7cae9))
* proper fallback if missing paths config modules ([7067e9e](https://github.com/unraid/api/commit/7067e9e3dd3966309013b52c90090cc82de4e4fb))
* rc.unraid-api now cleans up older dependencies ([#1404](https://github.com/unraid/api/issues/1404)) ([83076bb](https://github.com/unraid/api/commit/83076bb94088095de8b1a332a50bbef91421f0c1))
* remote access lifecycle during boot & shutdown ([#1422](https://github.com/unraid/api/issues/1422)) ([7bc583b](https://github.com/unraid/api/commit/7bc583b18621c8140232772ca36c6d9b8d8a9cd7))
* sign out correctly on error ([#1452](https://github.com/unraid/api/issues/1452)) ([d08fc94](https://github.com/unraid/api/commit/d08fc94afb94e386907da44402ee5a24cfb3d00a))
* simplify usb listing ([#1402](https://github.com/unraid/api/issues/1402)) ([5355115](https://github.com/unraid/api/commit/5355115af2f4122af9afa3f63ed8f830b33cbf5c))
* theme issues when sent from graph ([#1424](https://github.com/unraid/api/issues/1424)) ([75ad838](https://github.com/unraid/api/commit/75ad8381bd4f4045ab1d3aa84e08ecddfba27617))
* **ui:** notifications positioning regression ([#1445](https://github.com/unraid/api/issues/1445)) ([f73e5e0](https://github.com/unraid/api/commit/f73e5e0058fcc3bedebfbe7380ffcb44aea981b8))
* use some instead of every for connect detection ([9ce2fee](https://github.com/unraid/api/commit/9ce2fee380c4db1395f5d4df7f16ae6c57d1a748))
### Reverts
* revert package.json dependency updates from commit 711cc9a for api and packages/* ([94420e4](https://github.com/unraid/api/commit/94420e4d45735b8def3915b5789c15c1c3121f1e))
## [4.8.0](https://github.com/unraid/api/compare/v4.7.0...v4.8.0) (2025-05-01)
### Features
* move activation code logic into the API ([#1369](https://github.com/unraid/api/issues/1369)) ([39e83b2](https://github.com/unraid/api/commit/39e83b2aa156586ab4da362137194280fccefe7c))
### Bug Fixes
* 400 error when submitting connect settings ([831050f](https://github.com/unraid/api/commit/831050f4e8c3af4cbcc123a3a609025f250f0824))
## [4.7.0](https://github.com/unraid/api/compare/v4.6.6...v4.7.0) (2025-04-24)

View File

@@ -1,7 +1,7 @@
###########################################################
# Development/Build Image
###########################################################
FROM node:22-bookworm-slim AS development
FROM node:22.17.0-bookworm-slim AS development
# Install build tools and dependencies
RUN apt-get update -y && apt-get install -y \

View File

@@ -1,5 +1,5 @@
[api]
version="4.6.6"
version="4.4.1"
extraOrigins="https://google.com,https://test.com"
[local]
sandbox="yes"

View File

@@ -0,0 +1,13 @@
{
"code": "EXAMPLE_CODE_123",
"partnerName": "MyPartner Inc.",
"partnerUrl": "https://partner.example.com",
"serverName": "MyAwesomeServer",
"sysModel": "CustomBuild v1.0",
"comment": "This is a test activation code for development.",
"header": "#336699",
"headermetacolor": "#FFFFFF",
"background": "#F0F0F0",
"showBannerGradient": "yes",
"theme": "black"
}

View File

@@ -0,0 +1 @@
true

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8" ?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="442" height="221">
<defs>
<linearGradient id="gradient_0" gradientUnits="userSpaceOnUse" x1="608.84924" y1="48.058002" x2="447.47684" y2="388.15295">
<stop offset="0" stop-color="#ECC02F"/>
<stop offset="1" stop-color="#B8436B"/>
</linearGradient>
</defs>
<path fill="url(#gradient_0)" transform="scale(0.431641 0.431641)" d="M126.543 236.139C141.269 184.983 170.747 148.08 228.938 144.823C240.378 144.182 259.66 144.749 271.333 145.215C299.585 144.391 350.558 142.667 377.842 145.685C414.099 149.696 443.185 175.429 472.192 195.251L586.561 274.337C636.114 308.874 627.234 309.151 685.21 309.042L778.304 309.082C799.091 309.099 813.482 308.867 828.82 292.529C857.893 261.561 843.003 209.317 800.506 200.17C790.505 198.018 779.334 199.535 769.11 199.523L702.658 199.488C690.005 186.062 675.199 151.817 658.182 145.215L739.199 145.198C765.636 145.196 796.164 142.886 821.565 150.344C923.889 180.389 922.324 331.136 816.611 357.807C802.524 361.361 788.425 361.034 774.035 361.031L663.497 361.009C623.773 360.859 603.599 349.313 572.35 327.596L430.421 229.848C415.731 219.804 401.419 209.118 386.451 199.488C377.579 199.501 368.42 200.01 359.582 199.488L272.561 199.497C258.582 199.485 235.352 198.06 222.607 200.981C192.741 207.825 177.956 234.361 180.015 263.294C177.545 260.392 178.63 254.678 178.838 251.164C179.877 233.569 187.409 224.968 197.345 212.22C184.786 202.853 156.933 193.749 149.447 186.645C143.454 196.583 136.881 205.628 132.955 216.732C130.766 222.921 130.678 230.967 127.506 236.625L126.543 236.139Z"/>
<path fill="#308DAF" transform="scale(0.431641 0.431641)" d="M149.447 186.645C156.933 193.749 184.786 202.853 197.345 212.22C187.409 224.968 179.877 233.569 178.838 251.164C178.63 254.678 177.545 260.392 180.015 263.294C192.489 309.751 221.563 309.078 263.512 309.07L322.096 309.048C333.708 325.984 348.958 344.904 361.795 361.006L232.654 361.03C176.801 360.579 130.605 315.939 126.498 260.613C125.893 252.473 126.453 244.293 126.543 236.139L127.506 236.625C130.678 230.967 130.766 222.921 132.955 216.732C136.881 205.628 143.454 196.583 149.447 186.645Z"/>
<defs>
<linearGradient id="gradient_1" gradientUnits="userSpaceOnUse" x1="620.42566" y1="140.57172" x2="611.08759" y2="282.2207">
<stop offset="0" stop-color="#F5A22C"/>
<stop offset="1" stop-color="#E17543"/>
</linearGradient>
</defs>
<path fill="url(#gradient_1)" transform="scale(0.431641 0.431641)" d="M570.215 137.504C646.214 133.055 670.623 188.789 707.064 241.977L726.71 270.658C729.065 274.1 737.591 284.13 737.576 287.916L674.645 287.916C674.5 287.132 659.251 264.134 658.182 263.294C658.133 262.92 623.915 212.832 620.593 208.697C602.652 186.369 565.856 181.796 545.393 203.424C542.002 207.007 539.705 211.779 535.713 214.764C534.409 212.586 496.093 187.105 490.641 183.32C508.306 154.99 539.004 142.872 570.215 137.504Z"/>
<path fill="#308DAF" transform="scale(0.431641 0.431641)" d="M286.656 221.485L350.512 221.485C354.248 227.374 358.556 232.986 362.565 238.698L379.9 263.82C397.44 289.065 410.994 321.185 447.698 317.317C464.599 315.536 476.472 305.449 486.751 292.741C494.293 298.818 530.089 320.341 533.124 324.28C532.441 328.231 526.229 334.319 522.861 336.255C521.587 339.958 509.164 348.519 505.635 350.88C463.781 378.879 411.472 377.537 373.808 343.464C365.331 335.795 359.734 326.969 353.351 317.641L336.798 293.614C320.035 269.591 302.915 245.863 286.656 221.485Z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

10
api/dev/configs/api.json Normal file
View File

@@ -0,0 +1,10 @@
{
"version": "4.8.0",
"extraOrigins": [
"https://google.com",
"https://test.com"
],
"sandbox": true,
"ssoSubIds": [],
"plugins": ["unraid-api-plugin-connect"]
}

View File

@@ -1,23 +1,16 @@
{
"demo": "2025-04-21T14:27:27.631Z",
"wanaccess": "yes",
"wanport": "8443",
"upnpEnabled": "no",
"apikey": "_______________________BIG_API_KEY_HERE_________________________",
"localApiKey": "_______________________LOCAL_API_KEY_HERE_________________________",
"email": "test@example.com",
"username": "zspearmint",
"avatar": "https://via.placeholder.com/200",
"regWizTime": "1611175408732_0951-1653-3509-FBA155FA23C0",
"wanaccess": false,
"wanport": 0,
"upnpEnabled": false,
"apikey": "",
"localApiKey": "",
"email": "",
"username": "",
"avatar": "",
"regWizTime": "",
"accesstoken": "",
"idtoken": "",
"refreshtoken": "",
"dynamicRemoteAccessType": "DISABLED",
"ssoSubIds": "",
"version": "4.6.6",
"extraOrigins": [
"https://google.com",
"https://test.com"
],
"sandbox": "yes"
"ssoSubIds": []
}

View File

@@ -1,36 +1,42 @@
[display]
date="%c"
time="%I:%M %p"
number=".,"
scale="-1"
tabs="1"
users="Tasks:3"
resize="0"
wwn="0"
total="1"
usage="0"
banner="image"
dashapps="icons"
theme="white"
text="1"
unit="C"
warning="70"
critical="90"
hot="45"
max="55"
sysinfo="/Tools/SystemProfiler"
date=%c
time=%I:%M %p
number=.,
scale=-1
tabs=1
users=Tasks:3
resize=0
wwn=0
total=1
usage=0
banner=image
dashapps=icons
theme=black
text=1
unit=C
warning=70
critical=90
hot=45
max=55
sysinfo=/Tools/SystemProfiler
header=336699
headermetacolor=FFFFFF
background=F0F0F0
showBannerGradient=yes
[notify]
entity="1"
normal="1"
warning="1"
alert="1"
unraid="1"
plugin="1"
docker_notify="1"
report="1"
display="0"
date="d-m-Y"
time="H:i"
position="top-right"
path="./dev/notifications"
system="*/1 * * * *"
entity=1
normal=1
warning=1
alert=1
unraid=1
plugin=1
docker_notify=1
report=1
display=0
date=d-m-Y
time=H:i
position=top-right
path=./dev/notifications
system=*/1 * * * *

36
api/dev/ident.cfg Normal file
View File

@@ -0,0 +1,36 @@
# Generated settings:
NAME="Unraid"
timeZone="America/New_York"
COMMENT="Media server"
SECURITY="user"
WORKGROUP="WORKGROUP"
DOMAIN=""
DOMAIN_SHORT=""
hideDotFiles="no"
enableFruit="yes"
USE_NETBIOS="no"
localMaster="yes"
serverMultiChannel="no"
USE_WSD="yes"
WSD_OPT=""
WSD2_OPT=""
USE_NTP="yes"
NTP_SERVER1="time1.google.com"
NTP_SERVER2="time2.google.com"
NTP_SERVER3="time3.google.com"
NTP_SERVER4="time4.google.com"
DOMAIN_LOGIN="Administrator"
DOMAIN_PASSWD=""
SYS_MODEL="Custom"
SYS_ARRAY_SLOTS="24"
USE_SSL="yes"
PORT="80"
PORTSSL="8443"
LOCAL_TLD="local"
BIND_MGT="no"
USE_TELNET="no"
PORTTELNET="23"
USE_SSH="yes"
PORTSSH="22"
USE_UPNP="yes"
START_PAGE="Main"

View File

@@ -1,5 +1,5 @@
[api]
version="4.6.6"
version="4.4.1"
extraOrigins="https://google.com,https://test.com"
[local]
sandbox="yes"
@@ -20,5 +20,5 @@ dynamicRemoteAccessType="DISABLED"
ssoSubIds=""
allowedOrigins="/var/run/unraid-notifications.sock, /var/run/unraid-php.sock, /var/run/unraid-cli.sock, http://localhost:8080, https://localhost:4443, https://tower.local:4443, https://192.168.1.150:4443, https://tower:4443, https://192-168-1-150.thisisfourtyrandomcharacters012345678900.myunraid.net:4443, https://85-121-123-122.thisisfourtyrandomcharacters012345678900.myunraid.net:8443, https://10-252-0-1.hash.myunraid.net:4443, https://10-252-1-1.hash.myunraid.net:4443, https://10-253-3-1.hash.myunraid.net:4443, https://10-253-4-1.hash.myunraid.net:4443, https://10-253-5-1.hash.myunraid.net:4443, https://10-100-0-1.hash.myunraid.net:4443, https://10-100-0-2.hash.myunraid.net:4443, https://10-123-1-2.hash.myunraid.net:4443, https://221-123-121-112.hash.myunraid.net:4443, https://google.com, https://test.com, https://connect.myunraid.net, https://connect-staging.myunraid.net, https://dev-my.myunraid.net:4000, https://studio.apollographql.com"
[connectionStatus]
minigraph="ERROR_RETRYING"
minigraph="PRE_INIT"
upnpStatus=""

View File

@@ -102,6 +102,7 @@ regTm="1833409182"
regTm2="0"
regExp=""
regGen="0"
regState="ENOKEYFILE"
sbName="/boot/config/super.dat"
sbVersion="2.9.13"
sbUpdated="1596079143"

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 222.36 39.04"><defs><linearGradient id="header-logo" x1="47.53" y1="79.1" x2="170.71" y2="-44.08" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#e32929"/><stop offset="1" stop-color="#ff8d30"/></linearGradient></defs><title>unraid.net</title><path d="M146.7,29.47H135l-3,9h-6.49L138.93,0h8l13.41,38.49h-7.09L142.62,6.93l-5.83,16.88h8ZM29.69,0V25.4c0,8.91-5.77,13.64-14.9,13.64S0,34.31,0,25.4V0H6.54V25.4c0,5.17,3.19,7.92,8.25,7.92s8.36-2.75,8.36-7.92V0ZM50.86,12v26.5H44.31V0h6.11l17,26.5V0H74V38.49H67.9ZM171.29,0h6.54V38.49h-6.54Zm51.07,24.69c0,9-5.88,13.8-15.17,13.8H192.67V0H207.3c9.18,0,15.06,4.78,15.06,13.8ZM215.82,13.8c0-5.28-3.3-8.14-8.52-8.14h-8.08V32.77h8c5.33,0,8.63-2.8,8.63-8.08ZM108.31,23.92c4.34-1.6,6.93-5.28,6.93-11.55C115.24,3.68,110.18,0,102.48,0H88.84V38.49h6.55V5.66h6.87c3.8,0,6.21,1.82,6.21,6.71s-2.41,6.76-6.21,6.76H98.88l9.21,19.36h7.53Z" fill="url(#header-logo)"/></svg>

After

Width:  |  Height:  |  Size: 1008 B

View File

@@ -10,22 +10,115 @@ where the API provides dependencies for the plugin while the plugin provides fun
### Adding a local workspace package as an API plugin
The challenge with local workspace plugins is that they aren't available via npm during production.
To solve this, we vendor them inside `dist/plugins`. To prevent the build from breaking, however,
you should mark the workspace dependency as optional. For example:
To solve this, we vendor them during the build process. Here's the complete process:
#### 1. Configure the build system
Add your workspace package to the vendoring configuration in `api/scripts/build.ts`:
```typescript
const WORKSPACE_PACKAGES_TO_VENDOR = {
'@unraid/shared': 'packages/unraid-shared',
'unraid-api-plugin-connect': 'packages/unraid-api-plugin-connect',
'your-plugin-name': 'packages/your-plugin-path', // Add your plugin here
} as const;
```
#### 2. Configure Vite
Add your workspace package to the Vite configuration in `api/vite.config.ts`:
```typescript
const workspaceDependencies = {
'@unraid/shared': 'packages/unraid-shared',
'unraid-api-plugin-connect': 'packages/unraid-api-plugin-connect',
'your-plugin-name': 'packages/your-plugin-path', // Add your plugin here
};
```
This ensures the package is:
- Excluded from Vite's optimization during development
- Marked as external during the build process
- Properly handled in SSR mode
#### 3. Configure the API package.json
Add your workspace package as a peer dependency in `api/package.json`:
```json
{
"peerDependencies": {
"unraid-api-plugin-connect": "workspace:*"
"unraid-api-plugin-connect": "workspace:*",
"your-plugin-name": "workspace:*"
},
"peerDependenciesMeta": {
"unraid-api-plugin-connect": {
"optional": true
},
"your-plugin-name": {
"optional": true
}
},
}
}
```
By marking the workspace dependency "optional", npm will not attempt to install it.
Thus, even though the "workspace:*" identifier will be invalid during build-time and run-time,
it will not cause problems.
By marking the workspace dependency "optional", npm will not attempt to install it during development.
The "workspace:*" identifier will be invalid during build-time and run-time, but won't cause problems
because the package gets vendored instead.
#### 4. Plugin package setup
Your workspace plugin package should:
1. **Export types and main entry**: Set up proper `main`, `types`, and `exports` fields:
```json
{
"name": "your-plugin-name",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"files": ["dist"]
}
```
2. **Use peer dependencies**: Declare shared dependencies as peer dependencies to avoid duplication:
```json
{
"peerDependencies": {
"@nestjs/common": "^11.0.11",
"@nestjs/core": "^11.0.11",
"graphql": "^16.9.0"
}
}
```
3. **Include build script**: Add a build script that compiles TypeScript:
```json
{
"scripts": {
"build": "tsc",
"prepare": "npm run build"
}
}
```
#### 5. Build process
During production builds:
1. The build script (`api/scripts/build.ts`) will automatically pack and install your workspace package as a tarball
2. This happens after `npm install --omit=dev` in the pack directory
3. The vendored package becomes a regular node_modules dependency in the final build
#### 6. Development vs Production
- **Development**: Vite resolves workspace packages directly from their source
- **Production**: Packages are vendored as tarballs in `node_modules`
This approach ensures that workspace plugins work seamlessly in both development and production environments.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "@unraid/api",
"version": "4.7.0",
"version": "4.9.2",
"main": "src/cli/index.ts",
"type": "module",
"corepack": {
@@ -10,18 +10,19 @@
"author": "Lime Technology, Inc. <unraid.net>",
"license": "GPL-2.0-or-later",
"engines": {
"pnpm": ">=8.0.0"
"pnpm": "10.13.1"
},
"scripts": {
"// Development": "",
"start": "node dist/main.js",
"dev": "vite",
"dev:debug": "NODE_OPTIONS='--inspect-brk=9229 --enable-source-maps' vite",
"command": "pnpm run build && clear && ./dist/cli.js",
"command:raw": "./dist/cli.js",
"// Build and Deploy": "",
"build": "vite build --mode=production",
"postbuild": "chmod +x dist/main.js && chmod +x dist/cli.js && node scripts/copy-plugins.js",
"build:watch": "nodemon --watch src --ext ts,js,json --exec 'tsx ./scripts/build.ts'",
"postbuild": "chmod +x dist/main.js && chmod +x dist/cli.js",
"build:watch": "WATCH_MODE=true nodemon --watch src --ext ts,js,json --exec 'tsx ./scripts/build.ts'",
"build:docker": "./scripts/dc.sh run --rm builder",
"build:release": "tsx ./scripts/build.ts",
"preunraid:deploy": "pnpm build",
@@ -51,96 +52,97 @@
"unraid-api": "dist/cli.js"
},
"dependencies": {
"@apollo/client": "^3.11.8",
"@apollo/server": "^4.11.2",
"@as-integrations/fastify": "^2.1.1",
"@fastify/cookie": "^11.0.2",
"@fastify/helmet": "^13.0.1",
"@graphql-codegen/client-preset": "^4.5.0",
"@graphql-tools/load-files": "^7.0.0",
"@graphql-tools/merge": "^9.0.8",
"@graphql-tools/schema": "^10.0.7",
"@graphql-tools/utils": "^10.5.5",
"@jsonforms/core": "^3.5.1",
"@nestjs/apollo": "^13.0.3",
"@nestjs/cache-manager": "^3.0.1",
"@nestjs/common": "^11.0.11",
"@nestjs/config": "^4.0.2",
"@nestjs/core": "^11.0.11",
"@nestjs/graphql": "^13.0.3",
"@nestjs/passport": "^11.0.0",
"@nestjs/platform-fastify": "^11.0.11",
"@nestjs/schedule": "^5.0.0",
"@nestjs/throttler": "^6.2.1",
"@reduxjs/toolkit": "^2.3.0",
"@runonflux/nat-upnp": "^1.0.2",
"@types/diff": "^7.0.1",
"@unraid/libvirt": "^2.1.0",
"accesscontrol": "^2.2.1",
"bycontract": "^2.0.11",
"bytes": "^3.1.2",
"cache-manager": "^6.4.2",
"cacheable-lookup": "^7.0.0",
"camelcase-keys": "^9.1.3",
"casbin": "^5.32.0",
"change-case": "^5.4.4",
"chokidar": "^4.0.1",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"cli-table": "^0.3.11",
"command-exists": "^1.2.9",
"convert": "^5.8.0",
"cookie": "^1.0.2",
"cron": "3.5.0",
"cross-fetch": "^4.0.0",
"diff": "^7.0.0",
"dockerode": "^4.0.5",
"dotenv": "^16.4.5",
"execa": "^9.5.1",
"exit-hook": "^4.0.0",
"fastify": "^5.2.1",
"filenamify": "^6.0.0",
"fs-extra": "^11.2.0",
"glob": "^11.0.1",
"global-agent": "^3.0.0",
"got": "^14.4.6",
"graphql": "^16.9.0",
"graphql-fields": "^2.0.3",
"graphql-scalars": "^1.23.0",
"graphql-subscriptions": "^3.0.0",
"graphql-tag": "^2.12.6",
"graphql-type-json": "^0.3.2",
"graphql-type-uuid": "^0.2.0",
"graphql-ws": "^6.0.0",
"ini": "^5.0.0",
"ip": "^2.0.1",
"jose": "^6.0.0",
"lodash-es": "^4.17.21",
"multi-ini": "^2.3.2",
"mustache": "^4.2.0",
"nest-authz": "^2.14.0",
"nest-commander": "^3.15.0",
"nestjs-pino": "^4.1.0",
"node-cache": "^5.1.2",
"node-window-polyfill": "^1.0.2",
"p-retry": "^6.2.0",
"passport-custom": "^1.1.1",
"passport-http-header-strategy": "^1.1.0",
"path-type": "^6.0.0",
"pino": "^9.5.0",
"pino-http": "^10.3.0",
"pino-pretty": "^13.0.0",
"pm2": "^6.0.0",
"@apollo/client": "3.13.8",
"@apollo/server": "4.12.2",
"@as-integrations/fastify": "2.1.1",
"@fastify/cookie": "11.0.2",
"@fastify/helmet": "13.0.1",
"@graphql-codegen/client-preset": "4.8.3",
"@graphql-tools/load-files": "7.0.1",
"@graphql-tools/merge": "9.0.24",
"@graphql-tools/schema": "10.0.23",
"@graphql-tools/utils": "10.8.6",
"@jsonforms/core": "3.6.0",
"@nestjs/apollo": "13.1.0",
"@nestjs/cache-manager": "3.0.1",
"@nestjs/common": "11.1.3",
"@nestjs/config": "4.0.2",
"@nestjs/core": "11.1.3",
"@nestjs/event-emitter": "3.0.1",
"@nestjs/graphql": "13.1.0",
"@nestjs/passport": "11.0.5",
"@nestjs/platform-fastify": "11.1.3",
"@nestjs/schedule": "6.0.0",
"@nestjs/throttler": "6.4.0",
"@reduxjs/toolkit": "2.8.2",
"@runonflux/nat-upnp": "1.0.2",
"@types/diff": "8.0.0",
"@unraid/libvirt": "2.1.0",
"@unraid/shared": "workspace:*",
"accesscontrol": "2.2.1",
"bycontract": "2.0.11",
"bytes": "3.1.2",
"cache-manager": "7.0.1",
"cacheable-lookup": "7.0.0",
"camelcase-keys": "9.1.3",
"casbin": "5.38.0",
"change-case": "5.4.4",
"chokidar": "4.0.3",
"class-transformer": "0.5.1",
"class-validator": "0.14.2",
"cli-table": "0.3.11",
"command-exists": "1.2.9",
"convert": "5.12.0",
"cookie": "1.0.2",
"cron": "4.3.1",
"cross-fetch": "4.1.0",
"diff": "8.0.2",
"dockerode": "4.0.7",
"dotenv": "17.1.0",
"execa": "9.6.0",
"exit-hook": "4.0.0",
"fastify": "5.4.0",
"filenamify": "6.0.0",
"fs-extra": "11.3.0",
"glob": "11.0.3",
"global-agent": "3.0.0",
"got": "14.4.7",
"graphql": "16.11.0",
"graphql-fields": "2.0.3",
"graphql-scalars": "1.24.2",
"graphql-subscriptions": "3.0.0",
"graphql-tag": "2.12.6",
"graphql-ws": "6.0.5",
"ini": "5.0.0",
"ip": "2.0.1",
"jose": "6.0.11",
"json-bigint-patch": "0.0.8",
"lodash-es": "4.17.21",
"multi-ini": "2.3.2",
"mustache": "4.2.0",
"nest-authz": "2.17.0",
"nest-commander": "3.17.0",
"nestjs-pino": "4.4.0",
"node-cache": "5.1.2",
"node-window-polyfill": "1.0.4",
"p-retry": "6.2.1",
"passport-custom": "1.1.1",
"passport-http-header-strategy": "1.1.0",
"path-type": "6.0.0",
"pino": "9.7.0",
"pino-http": "10.5.0",
"pino-pretty": "13.0.0",
"pm2": "6.0.8",
"reflect-metadata": "^0.1.14",
"request": "^2.88.2",
"rxjs": "^7.8.2",
"semver": "^7.6.3",
"strftime": "^0.10.3",
"systeminformation": "^5.25.11",
"uuid": "^11.0.2",
"ws": "^8.18.0",
"zen-observable-ts": "^1.1.0",
"zod": "^3.23.8"
"request": "2.88.2",
"rxjs": "7.8.2",
"semver": "7.7.2",
"strftime": "0.10.3",
"systeminformation": "5.27.7",
"uuid": "11.1.0",
"ws": "8.18.3",
"zen-observable-ts": "1.1.0",
"zod": "3.25.76"
},
"peerDependencies": {
"unraid-api-plugin-connect": "workspace:*"
@@ -151,71 +153,71 @@
}
},
"devDependencies": {
"@eslint/js": "^9.21.0",
"@graphql-codegen/add": "^5.0.3",
"@graphql-codegen/cli": "^5.0.3",
"@graphql-codegen/fragment-matcher": "^5.0.2",
"@graphql-codegen/import-types-preset": "^3.0.0",
"@graphql-codegen/typed-document-node": "^5.0.11",
"@graphql-codegen/typescript": "^4.1.1",
"@graphql-codegen/typescript-operations": "^4.3.1",
"@graphql-codegen/typescript-resolvers": "4.5.0",
"@graphql-typed-document-node/core": "^3.2.0",
"@ianvs/prettier-plugin-sort-imports": "^4.4.0",
"@nestjs/testing": "^11.0.11",
"@originjs/vite-plugin-commonjs": "^1.0.3",
"@rollup/plugin-node-resolve": "^16.0.0",
"@swc/core": "^1.10.1",
"@types/async-exit-hook": "^2.0.2",
"@types/bytes": "^3.1.4",
"@types/cli-table": "^0.3.4",
"@types/command-exists": "^1.2.3",
"@types/cors": "^2.8.17",
"@types/dockerode": "^3.3.31",
"@types/graphql-fields": "^1.3.9",
"@types/graphql-type-uuid": "^0.2.6",
"@types/ini": "^4.1.1",
"@types/ip": "^1.1.3",
"@types/lodash": "^4.17.13",
"@types/lodash-es": "^4.17.12",
"@types/mustache": "^4.2.5",
"@types/node": "^22.13.4",
"@types/pify": "^6.0.0",
"@types/semver": "^7.5.8",
"@types/sendmail": "^1.4.7",
"@types/stoppable": "^1.1.3",
"@types/strftime": "^0.9.8",
"@types/uuid": "^10.0.0",
"@types/ws": "^8.5.13",
"@types/wtfnode": "^0.7.3",
"@vitest/coverage-v8": "^3.0.5",
"@vitest/ui": "^3.0.5",
"@eslint/js": "9.30.1",
"@graphql-codegen/add": "5.0.3",
"@graphql-codegen/cli": "5.0.7",
"@graphql-codegen/fragment-matcher": "5.1.0",
"@graphql-codegen/import-types-preset": "3.0.1",
"@graphql-codegen/typed-document-node": "5.1.2",
"@graphql-codegen/typescript": "4.1.6",
"@graphql-codegen/typescript-operations": "4.6.1",
"@graphql-codegen/typescript-resolvers": "4.5.1",
"@graphql-typed-document-node/core": "3.2.0",
"@ianvs/prettier-plugin-sort-imports": "4.4.2",
"@nestjs/testing": "11.1.3",
"@originjs/vite-plugin-commonjs": "1.0.3",
"@rollup/plugin-node-resolve": "16.0.1",
"@swc/core": "1.12.11",
"@types/async-exit-hook": "2.0.2",
"@types/bytes": "3.1.5",
"@types/cli-table": "0.3.4",
"@types/command-exists": "1.2.3",
"@types/cors": "2.8.19",
"@types/dockerode": "3.3.42",
"@types/graphql-fields": "1.3.9",
"@types/graphql-type-uuid": "0.2.6",
"@types/ini": "4.1.1",
"@types/ip": "1.1.3",
"@types/lodash": "4.17.20",
"@types/lodash-es": "4.17.12",
"@types/mustache": "4.2.6",
"@types/node": "22.16.2",
"@types/pify": "6.1.0",
"@types/semver": "7.7.0",
"@types/sendmail": "1.4.7",
"@types/stoppable": "1.1.3",
"@types/strftime": "0.9.8",
"@types/uuid": "10.0.0",
"@types/ws": "8.18.1",
"@types/wtfnode": "0.7.3",
"@vitest/coverage-v8": "3.2.4",
"@vitest/ui": "3.2.4",
"cz-conventional-changelog": "3.3.0",
"eslint": "^9.20.1",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-n": "^17.0.0",
"eslint-plugin-no-relative-import-paths": "^1.6.1",
"eslint-plugin-prettier": "^5.2.3",
"graphql-codegen-typescript-validation-schema": "^0.17.0",
"jiti": "^2.4.0",
"nodemon": "^3.1.7",
"prettier": "^3.5.2",
"rollup-plugin-node-externals": "^8.0.0",
"standard-version": "^9.5.0",
"tsx": "^4.19.2",
"type-fest": "^4.37.0",
"typescript": "^5.6.3",
"typescript-eslint": "^8.13.0",
"unplugin-swc": "^1.5.1",
"vite": "^6.0.0",
"vite-plugin-node": "^5.0.0",
"vite-tsconfig-paths": "^5.1.0",
"vitest": "^3.0.5",
"zx": "^8.3.2"
"eslint": "9.30.1",
"eslint-plugin-import": "2.32.0",
"eslint-plugin-n": "17.21.0",
"eslint-plugin-no-relative-import-paths": "1.6.1",
"eslint-plugin-prettier": "5.5.1",
"graphql-codegen-typescript-validation-schema": "0.17.1",
"jiti": "2.4.2",
"nodemon": "3.1.10",
"prettier": "3.6.2",
"rollup-plugin-node-externals": "8.0.1",
"commit-and-tag-version": "9.6.0",
"tsx": "4.20.3",
"type-fest": "4.41.0",
"typescript": "5.8.3",
"typescript-eslint": "8.36.0",
"unplugin-swc": "1.5.5",
"vite": "7.0.3",
"vite-plugin-node": "7.0.0",
"vite-tsconfig-paths": "5.1.4",
"vitest": "3.2.4",
"zx": "8.6.2"
},
"overrides": {
"eslint": {
"jiti": "2"
"jiti": "2.4.2"
},
"@as-integrations/fastify": {
"fastify": "$fastify"
@@ -226,5 +228,5 @@
}
},
"private": true,
"packageManager": "pnpm@10.8.1"
"packageManager": "pnpm@10.13.1"
}

View File

@@ -1,5 +1,7 @@
#!/usr/bin/env zx
import { mkdir, readFile, writeFile } from 'fs/promises';
import { existsSync } from 'node:fs';
import { basename, join, resolve } from 'node:path';
import { exit } from 'process';
import type { PackageJson } from 'type-fest';
@@ -10,8 +12,48 @@ import { getDeploymentVersion } from './get-deployment-version.js';
type ApiPackageJson = PackageJson & {
version: string;
peerDependencies: Record<string, string>;
dependencies?: Record<string, string>;
};
/**
* Map of workspace packages to vendor into production builds.
* Key: package name, Value: path from monorepo root to the package directory
*/
const WORKSPACE_PACKAGES_TO_VENDOR = {
'@unraid/shared': 'packages/unraid-shared',
'unraid-api-plugin-connect': 'packages/unraid-api-plugin-connect',
} as const;
/**
* Packs a workspace package and installs it as a tarball dependency.
*/
const packAndInstallWorkspacePackage = async (pkgName: string, pkgPath: string, tempDir: string) => {
const [fullPkgPath, fullTempDir] = [resolve(pkgPath), resolve(tempDir)];
if (!existsSync(fullPkgPath)) {
console.warn(`Workspace package ${pkgName} not found at ${fullPkgPath}. Skipping.`);
return;
}
console.log(`Building and packing workspace package ${pkgName}...`);
// Pack the package to a tarball
const packedResult = await $`pnpm --filter ${pkgName} pack --pack-destination ${fullTempDir}`;
const tarballPath = packedResult.lines().at(-1)!;
const tarballName = basename(tarballPath);
// Install the tarball
const tarballPattern = join(fullTempDir, tarballName);
await $`npm install ${tarballPattern}`;
};
/**------------------------------------------------------------------------
* Build Script
*
* Builds & vendors the API for deployment to an Unraid server.
*
* Places artifacts in the `deploy/` folder:
* - release/ contains source code & assets
* - node-modules-archive/ contains tarball of node_modules
*------------------------------------------------------------------------**/
try {
// Create release and pack directories
await mkdir('./deploy/release', { recursive: true });
@@ -30,6 +72,20 @@ try {
// Update the package.json version to the deployment version
parsedPackageJson.version = deploymentVersion;
/**---------------------------------------------
* Handle workspace runtime dependencies
*--------------------------------------------*/
const workspaceDeps = Object.keys(WORKSPACE_PACKAGES_TO_VENDOR);
if (workspaceDeps.length > 0) {
console.log(`Stripping workspace deps from package.json: ${workspaceDeps.join(', ')}`);
workspaceDeps.forEach((dep) => {
if (parsedPackageJson.dependencies?.[dep]) {
delete parsedPackageJson.dependencies[dep];
}
});
}
// omit dev dependencies from vendored dependencies in release build
parsedPackageJson.devDependencies = {};
@@ -49,13 +105,26 @@ try {
await writeFile('package.json', JSON.stringify(parsedPackageJson, null, 4));
const sudoCheck = await $`command -v sudo`.nothrow();
const SUDO = sudoCheck.exitCode === 0 ? 'sudo' : '';
await $`${SUDO} chown -R 0:0 node_modules`;
/** After npm install, vendor workspace packages via pack/install */
if (workspaceDeps.length > 0) {
console.log('Vendoring workspace packages...');
const tempDir = './packages';
await mkdir(tempDir, { recursive: true });
await $`XZ_OPT=-5 tar -cJf packed-node-modules.tar.xz node_modules`;
await $`mv packed-node-modules.tar.xz ../`;
await $`${SUDO} rm -rf node_modules`;
for (const dep of workspaceDeps) {
const pkgPath =
WORKSPACE_PACKAGES_TO_VENDOR[dep as keyof typeof WORKSPACE_PACKAGES_TO_VENDOR];
// The extra '../../../' prefix adjusts for the fact that we're in the pack directory.
// this way, pkgPath can be defined relative to the monorepo root.
await packAndInstallWorkspacePackage(dep, join('../../../', pkgPath), tempDir);
}
}
// Clean the release directory
await $`rm -rf ../release/*`;
// Copy other files to release directory
await $`cp -r ./* ../release/`;
// chmod the cli
await $`chmod +x ./dist/cli.js`;

View File

@@ -1,59 +0,0 @@
#!/usr/bin/env node
/**
* This AI-generated script copies workspace plugin dist folders to the dist/plugins directory
* to ensure they're available for dynamic imports in production.
*/
import { execSync } from 'child_process';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Get the package.json to find workspace dependencies
const packageJsonPath = path.resolve(__dirname, '../package.json');
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
// Create the plugins directory if it doesn't exist
const pluginsDir = path.resolve(__dirname, '../dist/plugins');
if (!fs.existsSync(pluginsDir)) {
fs.mkdirSync(pluginsDir, { recursive: true });
}
// Find all workspace plugins
const pluginPrefix = 'unraid-api-plugin-';
const workspacePlugins = Object.keys(packageJson.peerDependencies || {}).filter((pkgName) =>
pkgName.startsWith(pluginPrefix)
);
// Copy each plugin's dist folder to the plugins directory
for (const pkgName of workspacePlugins) {
const pluginPath = path.resolve(__dirname, `../../packages/${pkgName}`);
const pluginDistPath = path.resolve(pluginPath, 'dist');
const targetPath = path.resolve(pluginsDir, pkgName);
console.log(`Building ${pkgName}...`);
try {
execSync('pnpm build', {
cwd: pluginPath,
stdio: 'inherit',
});
console.log(`Successfully built ${pkgName}`);
} catch (error) {
console.error(`Failed to build ${pkgName}:`, error.message);
process.exit(1);
}
if (!fs.existsSync(pluginDistPath)) {
console.warn(`Plugin ${pkgName} dist folder not found at ${pluginDistPath}`);
process.exit(1);
}
console.log(`Copying ${pkgName} dist folder to ${targetPath}`);
fs.mkdirSync(targetPath, { recursive: true });
fs.cpSync(pluginDistPath, targetPath, { recursive: true });
console.log(`Successfully copied ${pkgName} dist folder`);
}
console.log('Plugin dist folders copied successfully');

View File

@@ -0,0 +1,137 @@
import { ConfigService } from '@nestjs/config';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { ApiConfigPersistence } from '@app/unraid-api/config/api-config.module.js';
import { ConfigPersistenceHelper } from '@app/unraid-api/config/persistence.helper.js';
describe('ApiConfigPersistence', () => {
let service: ApiConfigPersistence;
let configService: ConfigService;
let persistenceHelper: ConfigPersistenceHelper;
beforeEach(() => {
configService = {
get: vi.fn(),
set: vi.fn(),
} as any;
persistenceHelper = {} as ConfigPersistenceHelper;
service = new ApiConfigPersistence(configService, persistenceHelper);
});
describe('convertLegacyConfig', () => {
it('should migrate sandbox from string "yes" to boolean true', () => {
const legacyConfig = {
local: { sandbox: 'yes' },
api: { extraOrigins: '' },
remote: { ssoSubIds: '' },
};
const result = service.convertLegacyConfig(legacyConfig);
expect(result.sandbox).toBe(true);
});
it('should migrate sandbox from string "no" to boolean false', () => {
const legacyConfig = {
local: { sandbox: 'no' },
api: { extraOrigins: '' },
remote: { ssoSubIds: '' },
};
const result = service.convertLegacyConfig(legacyConfig);
expect(result.sandbox).toBe(false);
});
it('should migrate extraOrigins from comma-separated string to array', () => {
const legacyConfig = {
local: { sandbox: 'no' },
api: { extraOrigins: 'https://example.com,https://test.com' },
remote: { ssoSubIds: '' },
};
const result = service.convertLegacyConfig(legacyConfig);
expect(result.extraOrigins).toEqual(['https://example.com', 'https://test.com']);
});
it('should filter out non-HTTP origins from extraOrigins', () => {
const legacyConfig = {
local: { sandbox: 'no' },
api: {
extraOrigins: 'https://example.com,invalid-origin,http://test.com,ftp://bad.com',
},
remote: { ssoSubIds: '' },
};
const result = service.convertLegacyConfig(legacyConfig);
expect(result.extraOrigins).toEqual(['https://example.com', 'http://test.com']);
});
it('should handle empty extraOrigins string', () => {
const legacyConfig = {
local: { sandbox: 'no' },
api: { extraOrigins: '' },
remote: { ssoSubIds: '' },
};
const result = service.convertLegacyConfig(legacyConfig);
expect(result.extraOrigins).toEqual([]);
});
it('should migrate ssoSubIds from comma-separated string to array', () => {
const legacyConfig = {
local: { sandbox: 'no' },
api: { extraOrigins: '' },
remote: { ssoSubIds: 'user1,user2,user3' },
};
const result = service.convertLegacyConfig(legacyConfig);
expect(result.ssoSubIds).toEqual(['user1', 'user2', 'user3']);
});
it('should handle empty ssoSubIds string', () => {
const legacyConfig = {
local: { sandbox: 'no' },
api: { extraOrigins: '' },
remote: { ssoSubIds: '' },
};
const result = service.convertLegacyConfig(legacyConfig);
expect(result.ssoSubIds).toEqual([]);
});
it('should handle undefined config sections', () => {
const legacyConfig = {};
const result = service.convertLegacyConfig(legacyConfig);
expect(result.sandbox).toBe(false);
expect(result.extraOrigins).toEqual([]);
expect(result.ssoSubIds).toEqual([]);
});
it('should handle complete migration with all fields', () => {
const legacyConfig = {
local: { sandbox: 'yes' },
api: { extraOrigins: 'https://app1.example.com,https://app2.example.com' },
remote: { ssoSubIds: 'sub1,sub2,sub3' },
};
const result = service.convertLegacyConfig(legacyConfig);
expect(result.sandbox).toBe(true);
expect(result.extraOrigins).toEqual([
'https://app1.example.com',
'https://app2.example.com',
]);
expect(result.ssoSubIds).toEqual(['sub1', 'sub2', 'sub3']);
});
});
});

View File

@@ -1,29 +0,0 @@
import 'reflect-metadata';
import { readFileSync } from 'fs';
import { join } from 'path';
import { expect, test } from 'vitest';
import { checkMothershipAuthentication } from '@app/graphql/resolvers/query/cloud/check-mothership-authentication.js';
test('It fails to authenticate with mothership with no credentials', async () => {
try {
const packageJson = JSON.parse(readFileSync(join(process.cwd(), 'package.json'), 'utf-8'));
await expect(
checkMothershipAuthentication('BAD', 'BAD')
).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: Failed to connect to https://mothership.unraid.net/ws with a "426" HTTP error.]`
);
expect(packageJson.version).not.toBeNull();
await expect(
checkMothershipAuthentication(packageJson.version, 'BAD_API_KEY')
).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: Invalid credentials]`);
} catch (error) {
if (error instanceof Error && error.message.includes('Timeout')) {
// Test succeeds on timeout
return;
}
throw error;
}
});

View File

@@ -0,0 +1,374 @@
import { HTTPError } from 'got';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { RCloneApiService } from '@app/unraid-api/graph/resolvers/rclone/rclone-api.service.js';
import {
CreateRCloneRemoteDto,
DeleteRCloneRemoteDto,
GetRCloneJobStatusDto,
GetRCloneRemoteConfigDto,
GetRCloneRemoteDetailsDto,
RCloneStartBackupInput,
UpdateRCloneRemoteDto,
} from '@app/unraid-api/graph/resolvers/rclone/rclone.model.js';
vi.mock('got');
vi.mock('execa');
vi.mock('p-retry');
vi.mock('node:fs', () => ({
existsSync: vi.fn(),
}));
vi.mock('node:fs/promises', () => ({
mkdir: vi.fn(),
rm: vi.fn(),
writeFile: vi.fn(),
}));
vi.mock('@app/core/log.js', () => ({
sanitizeParams: vi.fn((params) => params),
}));
vi.mock('@app/store/index.js', () => ({
getters: {
paths: () => ({
'rclone-socket': '/tmp/rclone.sock',
'log-base': '/var/log',
}),
},
}));
// Mock NestJS Logger to suppress logs during tests
vi.mock('@nestjs/common', async (importOriginal) => {
const original = await importOriginal<typeof import('@nestjs/common')>();
return {
...original,
Logger: vi.fn(() => ({
log: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
debug: vi.fn(),
})),
};
});
describe('RCloneApiService', () => {
let service: RCloneApiService;
let mockGot: any;
let mockExeca: any;
let mockPRetry: any;
let mockExistsSync: any;
beforeEach(async () => {
vi.clearAllMocks();
const { default: got } = await import('got');
const { execa } = await import('execa');
const pRetry = await import('p-retry');
const { existsSync } = await import('node:fs');
mockGot = vi.mocked(got);
mockExeca = vi.mocked(execa);
mockPRetry = vi.mocked(pRetry.default);
mockExistsSync = vi.mocked(existsSync);
mockGot.post = vi.fn().mockResolvedValue({ body: {} });
mockExeca.mockReturnValue({
on: vi.fn(),
kill: vi.fn(),
killed: false,
pid: 12345,
} as any);
mockPRetry.mockResolvedValue(undefined);
mockExistsSync.mockReturnValue(false);
service = new RCloneApiService();
await service.onModuleInit();
});
describe('getProviders', () => {
it('should return list of providers', async () => {
const mockProviders = [
{ name: 'aws', prefix: 's3', description: 'Amazon S3' },
{ name: 'google', prefix: 'drive', description: 'Google Drive' },
];
mockGot.post.mockResolvedValue({
body: { providers: mockProviders },
});
const result = await service.getProviders();
expect(result).toEqual(mockProviders);
expect(mockGot.post).toHaveBeenCalledWith(
'http://unix:/tmp/rclone.sock:/config/providers',
expect.objectContaining({
json: {},
responseType: 'json',
enableUnixSockets: true,
})
);
});
it('should return empty array when no providers', async () => {
mockGot.post.mockResolvedValue({ body: {} });
const result = await service.getProviders();
expect(result).toEqual([]);
});
});
describe('listRemotes', () => {
it('should return list of remotes', async () => {
const mockRemotes = ['backup-s3', 'drive-storage'];
mockGot.post.mockResolvedValue({
body: { remotes: mockRemotes },
});
const result = await service.listRemotes();
expect(result).toEqual(mockRemotes);
expect(mockGot.post).toHaveBeenCalledWith(
'http://unix:/tmp/rclone.sock:/config/listremotes',
expect.objectContaining({
json: {},
})
);
});
it('should return empty array when no remotes', async () => {
mockGot.post.mockResolvedValue({ body: {} });
const result = await service.listRemotes();
expect(result).toEqual([]);
});
});
describe('getRemoteDetails', () => {
it('should return remote details', async () => {
const input: GetRCloneRemoteDetailsDto = { name: 'test-remote' };
const mockConfig = { type: 's3', provider: 'AWS' };
mockGot.post.mockResolvedValue({ body: mockConfig });
const result = await service.getRemoteDetails(input);
expect(result).toEqual(mockConfig);
expect(mockGot.post).toHaveBeenCalledWith(
'http://unix:/tmp/rclone.sock:/config/get',
expect.objectContaining({
json: { name: 'test-remote' },
})
);
});
});
describe('getRemoteConfig', () => {
it('should return remote configuration', async () => {
const input: GetRCloneRemoteConfigDto = { name: 'test-remote' };
const mockConfig = { type: 's3', access_key_id: 'AKIA...' };
mockGot.post.mockResolvedValue({ body: mockConfig });
const result = await service.getRemoteConfig(input);
expect(result).toEqual(mockConfig);
});
});
describe('createRemote', () => {
it('should create a new remote', async () => {
const input: CreateRCloneRemoteDto = {
name: 'new-remote',
type: 's3',
parameters: { access_key_id: 'AKIA...', secret_access_key: 'secret' },
};
const mockResponse = { success: true };
mockGot.post.mockResolvedValue({ body: mockResponse });
const result = await service.createRemote(input);
expect(result).toEqual(mockResponse);
expect(mockGot.post).toHaveBeenCalledWith(
'http://unix:/tmp/rclone.sock:/config/create',
expect.objectContaining({
json: {
name: 'new-remote',
type: 's3',
parameters: { access_key_id: 'AKIA...', secret_access_key: 'secret' },
},
})
);
});
});
describe('updateRemote', () => {
it('should update an existing remote', async () => {
const input: UpdateRCloneRemoteDto = {
name: 'existing-remote',
parameters: { access_key_id: 'NEW_AKIA...' },
};
const mockResponse = { success: true };
mockGot.post.mockResolvedValue({ body: mockResponse });
const result = await service.updateRemote(input);
expect(result).toEqual(mockResponse);
expect(mockGot.post).toHaveBeenCalledWith(
'http://unix:/tmp/rclone.sock:/config/update',
expect.objectContaining({
json: {
name: 'existing-remote',
access_key_id: 'NEW_AKIA...',
},
})
);
});
});
describe('deleteRemote', () => {
it('should delete a remote', async () => {
const input: DeleteRCloneRemoteDto = { name: 'remote-to-delete' };
const mockResponse = { success: true };
mockGot.post.mockResolvedValue({ body: mockResponse });
const result = await service.deleteRemote(input);
expect(result).toEqual(mockResponse);
expect(mockGot.post).toHaveBeenCalledWith(
'http://unix:/tmp/rclone.sock:/config/delete',
expect.objectContaining({
json: { name: 'remote-to-delete' },
})
);
});
});
describe('startBackup', () => {
it('should start a backup operation', async () => {
const input: RCloneStartBackupInput = {
srcPath: '/source/path',
dstPath: 'remote:backup/path',
options: { delete_on: 'dst' },
};
const mockResponse = { jobid: 'job-123' };
mockGot.post.mockResolvedValue({ body: mockResponse });
const result = await service.startBackup(input);
expect(result).toEqual(mockResponse);
expect(mockGot.post).toHaveBeenCalledWith(
'http://unix:/tmp/rclone.sock:/sync/copy',
expect.objectContaining({
json: {
srcFs: '/source/path',
dstFs: 'remote:backup/path',
delete_on: 'dst',
},
})
);
});
});
describe('getJobStatus', () => {
it('should return job status', async () => {
const input: GetRCloneJobStatusDto = { jobId: 'job-123' };
const mockStatus = { status: 'running', progress: 0.5 };
mockGot.post.mockResolvedValue({ body: mockStatus });
const result = await service.getJobStatus(input);
expect(result).toEqual(mockStatus);
expect(mockGot.post).toHaveBeenCalledWith(
'http://unix:/tmp/rclone.sock:/job/status',
expect.objectContaining({
json: { jobid: 'job-123' },
})
);
});
});
describe('listRunningJobs', () => {
it('should return list of running jobs', async () => {
const mockJobs = [
{ id: 'job-1', status: 'running' },
{ id: 'job-2', status: 'finished' },
];
mockGot.post.mockResolvedValue({ body: mockJobs });
const result = await service.listRunningJobs();
expect(result).toEqual(mockJobs);
expect(mockGot.post).toHaveBeenCalledWith(
'http://unix:/tmp/rclone.sock:/job/list',
expect.objectContaining({
json: {},
})
);
});
});
describe('error handling', () => {
it('should handle HTTP errors with detailed messages', async () => {
const httpError = {
name: 'HTTPError',
message: 'Request failed',
response: {
statusCode: 500,
body: JSON.stringify({ error: 'Internal server error' }),
},
};
Object.setPrototypeOf(httpError, HTTPError.prototype);
mockGot.post.mockRejectedValue(httpError);
await expect(service.getProviders()).rejects.toThrow(
'Rclone API Error (config/providers, HTTP 500): Rclone Error: Internal server error'
);
});
it('should handle HTTP errors with empty response body', async () => {
const httpError = {
name: 'HTTPError',
message: 'Request failed',
response: {
statusCode: 404,
body: '',
},
};
Object.setPrototypeOf(httpError, HTTPError.prototype);
mockGot.post.mockRejectedValue(httpError);
await expect(service.getProviders()).rejects.toThrow(
'Rclone API Error (config/providers, HTTP 404): Failed to process error response body. Raw body:'
);
});
it('should handle HTTP errors with malformed JSON', async () => {
const httpError = {
name: 'HTTPError',
message: 'Request failed',
response: {
statusCode: 400,
body: 'invalid json',
},
};
Object.setPrototypeOf(httpError, HTTPError.prototype);
mockGot.post.mockRejectedValue(httpError);
await expect(service.getProviders()).rejects.toThrow(
'Rclone API Error (config/providers, HTTP 400): Failed to process error response body. Raw body: invalid json'
);
});
it('should handle non-HTTP errors', async () => {
const networkError = new Error('Network connection failed');
mockGot.post.mockRejectedValue(networkError);
await expect(service.getProviders()).rejects.toThrow('Network connection failed');
});
it('should handle unknown errors', async () => {
mockGot.post.mockRejectedValue('unknown error');
await expect(service.getProviders()).rejects.toThrow(
'Unknown error calling RClone API (config/providers) with params {}: unknown error'
);
});
});
});

View File

@@ -1,227 +0,0 @@
import { expect, test, vi } from 'vitest';
import type { NginxUrlFields } from '@app/graphql/resolvers/subscription/network.js';
import { type Nginx } from '@app/core/types/states/nginx.js';
import {
getServerIps,
getUrlForField,
getUrlForServer,
} from '@app/graphql/resolvers/subscription/network.js';
import { store } from '@app/store/index.js';
import { loadConfigFile } from '@app/store/modules/config.js';
import { loadStateFiles } from '@app/store/modules/emhttp.js';
import { URL_TYPE } from '@app/unraid-api/graph/resolvers/connect/connect.model.js';
test.each([
[{ httpPort: 80, httpsPort: 443, url: 'my-default-url.com' }],
[{ httpPort: 123, httpsPort: 443, url: 'my-default-url.com' }],
[{ httpPort: 80, httpsPort: 12_345, url: 'my-default-url.com' }],
[{ httpPort: 212, httpsPort: 3_233, url: 'my-default-url.com' }],
[{ httpPort: 80, httpsPort: 443, url: 'https://BROKEN_URL' }],
])('getUrlForField', ({ httpPort, httpsPort, url }) => {
const responseInsecure = getUrlForField({
port: httpPort,
url,
});
const responseSecure = getUrlForField({
portSsl: httpsPort,
url,
});
if (httpPort === 80) {
expect(responseInsecure.port).toBe('');
} else {
expect(responseInsecure.port).toBe(httpPort.toString());
}
if (httpsPort === 443) {
expect(responseSecure.port).toBe('');
} else {
expect(responseSecure.port).toBe(httpsPort.toString());
}
});
test('getUrlForServer - field exists, ssl disabled', () => {
const result = getUrlForServer({
nginx: {
lanIp: '192.168.1.1',
sslEnabled: false,
httpPort: 123,
httpsPort: 445,
} as const as Nginx,
field: 'lanIp',
});
expect(result).toMatchInlineSnapshot('"http://192.168.1.1:123/"');
});
test('getUrlForServer - field exists, ssl yes', () => {
const result = getUrlForServer({
nginx: {
lanIp: '192.168.1.1',
sslEnabled: true,
sslMode: 'yes',
httpPort: 123,
httpsPort: 445,
} as const as Nginx,
field: 'lanIp',
});
expect(result).toMatchInlineSnapshot('"https://192.168.1.1:445/"');
});
test('getUrlForServer - field exists, ssl yes, port empty', () => {
const result = getUrlForServer({
nginx: {
lanIp: '192.168.1.1',
sslEnabled: true,
sslMode: 'yes',
httpPort: 80,
httpsPort: 443,
} as const as Nginx,
field: 'lanIp',
});
expect(result).toMatchInlineSnapshot('"https://192.168.1.1/"');
});
test('getUrlForServer - field exists, ssl auto', async () => {
const getResult = async () =>
getUrlForServer({
nginx: {
lanIp: '192.168.1.1',
sslEnabled: true,
sslMode: 'auto',
httpPort: 123,
httpsPort: 445,
} as const as Nginx,
field: 'lanIp',
});
await expect(getResult).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: Cannot get IP Based URL for field: "lanIp" SSL mode auto]`
);
});
test('getUrlForServer - field does not exist, ssl disabled', async () => {
const getResult = async () =>
getUrlForServer({
nginx: { lanIp: '192.168.1.1', sslEnabled: false, sslMode: 'no' } as const as Nginx,
ports: {
port: ':123',
portSsl: ':445',
defaultUrl: new URL('https://my-default-url.unraid.net'),
},
// @ts-expect-error Field doesn't exist
field: 'idontexist',
});
await expect(getResult).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: IP URL Resolver: Could not resolve any access URL for field: "idontexist", is FQDN?: false]`
);
});
test('getUrlForServer - FQDN - field exists, port non-empty', () => {
const result = getUrlForServer({
nginx: { lanFqdn: 'my-fqdn.unraid.net', httpsPort: 445 } as unknown as Nginx,
field: 'lanFqdn' as NginxUrlFields,
});
expect(result).toMatchInlineSnapshot('"https://my-fqdn.unraid.net:445/"');
});
test('getUrlForServer - FQDN - field exists, port empty', () => {
const result = getUrlForServer({
nginx: { lanFqdn: 'my-fqdn.unraid.net', httpPort: 80, httpsPort: 443 } as unknown as Nginx,
field: 'lanFqdn' as NginxUrlFields,
});
expect(result).toMatchInlineSnapshot('"https://my-fqdn.unraid.net/"');
});
test.each([
[
{
nginx: {
lanFqdn: 'my-fqdn.unraid.net',
sslEnabled: false,
sslMode: 'no',
httpPort: 80,
httpsPort: 443,
} as unknown as Nginx,
field: 'lanFqdn' as NginxUrlFields,
},
],
[
{
nginx: {
wanFqdn: 'my-fqdn.unraid.net',
sslEnabled: true,
sslMode: 'yes',
httpPort: 80,
httpsPort: 443,
} as unknown as Nginx,
field: 'wanFqdn' as NginxUrlFields,
},
],
[
{
nginx: {
wanFqdn6: 'my-fqdn.unraid.net',
sslEnabled: true,
sslMode: 'auto',
httpPort: 80,
httpsPort: 443,
} as unknown as Nginx,
field: 'wanFqdn6' as NginxUrlFields,
},
],
])('getUrlForServer - FQDN', ({ nginx, field }) => {
const result = getUrlForServer({ nginx, field });
expect(result.toString()).toBe('https://my-fqdn.unraid.net/');
});
test('getUrlForServer - field does not exist, ssl disabled', async () => {
const getResult = async () =>
getUrlForServer({
nginx: { lanFqdn: 'my-fqdn.unraid.net' } as unknown as Nginx,
ports: { portSsl: '', port: '', defaultUrl: new URL('https://my-default-url.unraid.net') },
// @ts-expect-error Field doesn't exist
field: 'idontexist',
});
await expect(getResult).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: IP URL Resolver: Could not resolve any access URL for field: "idontexist", is FQDN?: false]`
);
});
test('integration test, loading nginx ini and generating all URLs', async () => {
await store.dispatch(loadStateFiles());
await store.dispatch(loadConfigFile());
// Instead of mocking the getServerIps function, we'll use the actual function
// and verify the structure of the returned URLs
const urls = getServerIps();
// Verify that we have URLs
expect(urls.urls.length).toBeGreaterThan(0);
expect(urls.errors.length).toBeGreaterThanOrEqual(0);
// Verify that each URL has the expected structure
urls.urls.forEach((url) => {
expect(url).toHaveProperty('ipv4');
expect(url).toHaveProperty('name');
expect(url).toHaveProperty('type');
// Verify that the URL matches the expected pattern based on its type
if (url.type === URL_TYPE.DEFAULT) {
expect(url.ipv4?.toString()).toMatch(/^https:\/\/.*:\d+\/$/);
expect(url.ipv6?.toString()).toMatch(/^https:\/\/.*:\d+\/$/);
} else if (url.type === URL_TYPE.LAN) {
expect(url.ipv4?.toString()).toMatch(/^https:\/\/.*:\d+\/$/);
} else if (url.type === URL_TYPE.MDNS) {
expect(url.ipv4?.toString()).toMatch(/^https:\/\/.*:\d+\/$/);
} else if (url.type === URL_TYPE.WIREGUARD) {
expect(url.ipv4?.toString()).toMatch(/^https:\/\/.*:\d+\/$/);
}
});
// Verify that the error message contains the expected text
if (urls.errors.length > 0) {
expect(urls.errors[0].message).toContain(
'IP URL Resolver: Could not resolve any access URL for field:'
);
}
});

View File

@@ -0,0 +1,38 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`Returns paths 1`] = `
[
"core",
"unraid-api-base",
"unraid-data",
"docker-autostart",
"docker-socket",
"rclone-socket",
"parity-checks",
"htpasswd",
"emhttpd-socket",
"states",
"dynamix-base",
"dynamix-config",
"myservers-base",
"myservers-config",
"myservers-config-states",
"myservers-env",
"myservers-keepalive",
"keyfile-base",
"machine-id",
"log-base",
"unraid-log-base",
"var-run",
"auth-sessions",
"auth-keys",
"passwd",
"libvirt-pid",
"activationBase",
"webGuiBase",
"identConfig",
"activation",
"boot",
"webgui",
]
`;

View File

@@ -1,31 +1,14 @@
import { beforeEach, expect, test, vi } from 'vitest';
import { beforeEach, describe, expect, test, vi } from 'vitest';
import { pubsub, PUBSUB_CHANNEL } from '@app/core/pubsub.js';
import { GraphQLClient } from '@app/mothership/graphql-client.js';
import { stopPingTimeoutJobs } from '@app/mothership/jobs/ping-timeout-jobs.js';
import { setGraphqlConnectionStatus } from '@app/store/actions/set-minigraph-status.js';
import { setupRemoteAccessThunk } from '@app/store/actions/setup-remote-access.js';
import { store } from '@app/store/index.js';
import { MyServersConfigMemory } from '@app/types/my-servers-config.js';
import { MinigraphStatus } from '@app/unraid-api/graph/resolvers/cloud/cloud.model.js';
import {
WAN_ACCESS_TYPE,
WAN_FORWARD_TYPE,
} from '@app/unraid-api/graph/resolvers/connect/connect.model.js';
// Mock dependencies
vi.mock('@app/core/pubsub.js', () => {
const mockPublish = vi.fn();
return {
pubsub: {
publish: mockPublish,
},
PUBSUB_CHANNEL: {
OWNER: 'OWNER',
SERVERS: 'SERVERS',
},
__esModule: true,
default: {
describe.skip('config tests', () => {
// Mock dependencies
vi.mock('@app/core/pubsub.js', () => {
const mockPublish = vi.fn();
return {
pubsub: {
publish: mockPublish,
},
@@ -33,278 +16,288 @@ vi.mock('@app/core/pubsub.js', () => {
OWNER: 'OWNER',
SERVERS: 'SERVERS',
},
},
};
});
// Get the mock function for pubsub.publish
const mockPublish = vi.mocked(pubsub.publish);
// Clear mock before each test
beforeEach(() => {
mockPublish.mockClear();
});
vi.mock('@app/mothership/graphql-client.js', () => ({
GraphQLClient: {
clearInstance: vi.fn(),
},
}));
vi.mock('@app/mothership/jobs/ping-timeout-jobs.js', () => ({
stopPingTimeoutJobs: vi.fn(),
}));
const createConfigMatcher = (specificValues: Partial<MyServersConfigMemory> = {}) => {
const defaultMatcher = {
api: expect.objectContaining({
extraOrigins: expect.any(String),
version: expect.any(String),
}),
connectionStatus: expect.objectContaining({
minigraph: expect.any(String),
upnpStatus: expect.any(String),
}),
local: expect.objectContaining({
sandbox: expect.any(String),
}),
nodeEnv: expect.any(String),
remote: expect.objectContaining({
accesstoken: expect.any(String),
allowedOrigins: expect.any(String),
apikey: expect.any(String),
avatar: expect.any(String),
dynamicRemoteAccessType: expect.any(String),
email: expect.any(String),
idtoken: expect.any(String),
localApiKey: expect.any(String),
refreshtoken: expect.any(String),
regWizTime: expect.any(String),
ssoSubIds: expect.any(String),
upnpEnabled: expect.any(String),
username: expect.any(String),
wanaccess: expect.any(String),
wanport: expect.any(String),
}),
status: expect.any(String),
};
return expect.objectContaining({
...defaultMatcher,
...specificValues,
__esModule: true,
default: {
pubsub: {
publish: mockPublish,
},
PUBSUB_CHANNEL: {
OWNER: 'OWNER',
SERVERS: 'SERVERS',
},
},
};
});
};
test('Before init returns default values for all fields', async () => {
const state = store.getState().config;
expect(state).toMatchSnapshot();
}, 10_000);
// Get the mock function for pubsub.publish
const mockPublish = vi.mocked(pubsub.publish);
test('After init returns values from cfg file for all fields', async () => {
const { loadConfigFile } = await import('@app/store/modules/config.js');
// Clear mock before each test
beforeEach(() => {
mockPublish.mockClear();
});
// Load cfg into store
await store.dispatch(loadConfigFile());
vi.mock('@app/mothership/graphql-client.js', () => ({
GraphQLClient: {
clearInstance: vi.fn(),
},
}));
// Check if store has cfg contents loaded
const state = store.getState().config;
expect(state).toMatchObject(createConfigMatcher());
});
vi.mock('@app/mothership/jobs/ping-timeout-jobs.js', () => ({
stopPingTimeoutJobs: vi.fn(),
}));
test('updateUserConfig merges in changes to current state', async () => {
const { loadConfigFile, updateUserConfig } = await import('@app/store/modules/config.js');
// Load cfg into store
await store.dispatch(loadConfigFile());
// Update store
store.dispatch(
updateUserConfig({
remote: { avatar: 'https://via.placeholder.com/200' },
})
);
const state = store.getState().config;
expect(state).toMatchObject(
createConfigMatcher({
remote: expect.objectContaining({
avatar: 'https://via.placeholder.com/200',
const createConfigMatcher = (specificValues: Partial<MyServersConfigMemory> = {}) => {
const defaultMatcher = {
api: expect.objectContaining({
extraOrigins: expect.any(String),
version: expect.any(String),
}),
})
);
});
connectionStatus: expect.objectContaining({
minigraph: expect.any(String),
upnpStatus: expect.any(String),
}),
local: expect.objectContaining({
sandbox: expect.any(String),
}),
nodeEnv: expect.any(String),
remote: expect.objectContaining({
accesstoken: expect.any(String),
allowedOrigins: expect.any(String),
apikey: expect.any(String),
avatar: expect.any(String),
dynamicRemoteAccessType: expect.any(String),
email: expect.any(String),
idtoken: expect.any(String),
localApiKey: expect.any(String),
refreshtoken: expect.any(String),
regWizTime: expect.any(String),
ssoSubIds: expect.any(String),
upnpEnabled: expect.any(String),
username: expect.any(String),
wanaccess: expect.any(String),
wanport: expect.any(String),
}),
status: expect.any(String),
};
test('loginUser updates state and publishes to pubsub', async () => {
const { loginUser } = await import('@app/store/modules/config.js');
const userInfo = {
email: 'test@example.com',
avatar: 'https://via.placeholder.com/200',
username: 'testuser',
apikey: 'test-api-key',
localApiKey: 'test-local-api-key',
return expect.objectContaining({
...defaultMatcher,
...specificValues,
});
};
await store.dispatch(loginUser(userInfo));
// test('Before init returns default values for all fields', async () => {
// const state = store.getState().config;
// expect(state).toMatchSnapshot();
// }, 10_000);
expect(pubsub.publish).toHaveBeenCalledWith(PUBSUB_CHANNEL.OWNER, {
owner: {
username: userInfo.username,
url: '',
avatar: userInfo.avatar,
},
test('After init returns values from cfg file for all fields', async () => {
const { loadConfigFile } = await import('@app/store/modules/config.js');
// Load cfg into store
await store.dispatch(loadConfigFile());
// Check if store has cfg contents loaded
const state = store.getState().config;
expect(state).toMatchObject(createConfigMatcher());
});
const state = store.getState().config;
expect(state).toMatchObject(
createConfigMatcher({
remote: expect.objectContaining(userInfo),
})
);
});
test('updateUserConfig merges in changes to current state', async () => {
const { loadConfigFile, updateUserConfig } = await import('@app/store/modules/config.js');
test('logoutUser clears state and publishes to pubsub', async () => {
const { logoutUser } = await import('@app/store/modules/config.js');
// Load cfg into store
await store.dispatch(loadConfigFile());
await store.dispatch(logoutUser({ reason: 'test logout' }));
// Update store
store.dispatch(
updateUserConfig({
remote: { avatar: 'https://via.placeholder.com/200' },
})
);
expect(pubsub.publish).toHaveBeenCalledWith(PUBSUB_CHANNEL.SERVERS, { servers: [] });
expect(pubsub.publish).toHaveBeenCalledWith(PUBSUB_CHANNEL.OWNER, {
owner: {
username: 'root',
url: '',
avatar: '',
},
const state = store.getState().config;
expect(state).toMatchObject(
createConfigMatcher({
remote: expect.objectContaining({
avatar: 'https://via.placeholder.com/200',
}),
})
);
});
expect(stopPingTimeoutJobs).toHaveBeenCalled();
expect(GraphQLClient.clearInstance).toHaveBeenCalled();
});
test('updateAccessTokens updates token fields', async () => {
const { updateAccessTokens } = await import('@app/store/modules/config.js');
const tokens = {
accesstoken: 'new-access-token',
refreshtoken: 'new-refresh-token',
idtoken: 'new-id-token',
};
test('loginUser updates state and publishes to pubsub', async () => {
const { loginUser } = await import('@app/store/modules/config.js');
const userInfo = {
email: 'test@example.com',
avatar: 'https://via.placeholder.com/200',
username: 'testuser',
apikey: 'test-api-key',
localApiKey: 'test-local-api-key',
};
store.dispatch(updateAccessTokens(tokens));
await store.dispatch(loginUser(userInfo));
const state = store.getState().config;
expect(state).toMatchObject(
createConfigMatcher({
remote: expect.objectContaining(tokens),
})
);
});
expect(pubsub.publish).toHaveBeenCalledWith(PUBSUB_CHANNEL.OWNER, {
owner: {
username: userInfo.username,
url: '',
avatar: userInfo.avatar,
},
});
test('updateAllowedOrigins updates extraOrigins', async () => {
const { updateAllowedOrigins } = await import('@app/store/modules/config.js');
const origins = ['https://test1.com', 'https://test2.com'];
store.dispatch(updateAllowedOrigins(origins));
const state = store.getState().config;
expect(state.api.extraOrigins).toBe(origins.join(', '));
});
test('setUpnpState updates upnp settings', async () => {
const { setUpnpState } = await import('@app/store/modules/config.js');
store.dispatch(setUpnpState({ enabled: 'yes', status: 'active' }));
const state = store.getState().config;
expect(state.remote.upnpEnabled).toBe('yes');
expect(state.connectionStatus.upnpStatus).toBe('active');
});
test('setWanPortToValue updates wanport', async () => {
const { setWanPortToValue } = await import('@app/store/modules/config.js');
store.dispatch(setWanPortToValue(8443));
const state = store.getState().config;
expect(state.remote.wanport).toBe('8443');
});
test('setWanAccess updates wanaccess', async () => {
const { setWanAccess } = await import('@app/store/modules/config.js');
store.dispatch(setWanAccess('yes'));
const state = store.getState().config;
expect(state.remote.wanaccess).toBe('yes');
});
test('addSsoUser adds user to ssoSubIds', async () => {
const { addSsoUser } = await import('@app/store/modules/config.js');
store.dispatch(addSsoUser('user1'));
store.dispatch(addSsoUser('user2'));
const state = store.getState().config;
expect(state.remote.ssoSubIds).toBe('user1,user2');
});
test('removeSsoUser removes user from ssoSubIds', async () => {
const { addSsoUser, removeSsoUser } = await import('@app/store/modules/config.js');
store.dispatch(addSsoUser('user1'));
store.dispatch(addSsoUser('user2'));
store.dispatch(removeSsoUser('user1'));
const state = store.getState().config;
expect(state.remote.ssoSubIds).toBe('user2');
});
test('removeSsoUser with null clears all ssoSubIds', async () => {
const { addSsoUser, removeSsoUser } = await import('@app/store/modules/config.js');
store.dispatch(addSsoUser('user1'));
store.dispatch(addSsoUser('user2'));
store.dispatch(removeSsoUser(null));
const state = store.getState().config;
expect(state.remote.ssoSubIds).toBe('');
});
test('setLocalApiKey updates localApiKey', async () => {
const { setLocalApiKey } = await import('@app/store/modules/config.js');
store.dispatch(setLocalApiKey('new-local-api-key'));
const state = store.getState().config;
expect(state.remote.localApiKey).toBe('new-local-api-key');
});
test('setLocalApiKey with null clears localApiKey', async () => {
const { setLocalApiKey } = await import('@app/store/modules/config.js');
store.dispatch(setLocalApiKey(null));
const state = store.getState().config;
expect(state.remote.localApiKey).toBe('');
});
test('setGraphqlConnectionStatus updates minigraph status', async () => {
store.dispatch(setGraphqlConnectionStatus({ status: MinigraphStatus.CONNECTED, error: null }));
const state = store.getState().config;
expect(state.connectionStatus.minigraph).toBe(MinigraphStatus.CONNECTED);
});
test('setupRemoteAccessThunk.fulfilled updates remote access settings', async () => {
const remoteAccessSettings = {
accessType: WAN_ACCESS_TYPE.DYNAMIC,
forwardType: WAN_FORWARD_TYPE.UPNP,
};
await store.dispatch(setupRemoteAccessThunk(remoteAccessSettings));
const state = store.getState().config;
expect(state.remote).toMatchObject({
wanaccess: 'no',
dynamicRemoteAccessType: 'UPNP',
wanport: '',
upnpEnabled: 'yes',
const state = store.getState().config;
expect(state).toMatchObject(
createConfigMatcher({
remote: expect.objectContaining(userInfo),
})
);
});
test('logoutUser clears state and publishes to pubsub', async () => {
const { logoutUser } = await import('@app/store/modules/config.js');
await store.dispatch(logoutUser({ reason: 'test logout' }));
expect(pubsub.publish).toHaveBeenCalledWith(PUBSUB_CHANNEL.SERVERS, { servers: [] });
expect(pubsub.publish).toHaveBeenCalledWith(PUBSUB_CHANNEL.OWNER, {
owner: {
username: 'root',
url: '',
avatar: '',
},
});
// expect(stopPingTimeoutJobs).toHaveBeenCalled();
// expect(GraphQLClient.clearInstance).toHaveBeenCalled();
});
test('updateAccessTokens updates token fields', async () => {
const { updateAccessTokens } = await import('@app/store/modules/config.js');
const tokens = {
accesstoken: 'new-access-token',
refreshtoken: 'new-refresh-token',
idtoken: 'new-id-token',
};
store.dispatch(updateAccessTokens(tokens));
const state = store.getState().config;
expect(state).toMatchObject(
createConfigMatcher({
remote: expect.objectContaining(tokens),
})
);
});
test('updateAllowedOrigins updates extraOrigins', async () => {
const { updateAllowedOrigins } = await import('@app/store/modules/config.js');
const origins = ['https://test1.com', 'https://test2.com'];
store.dispatch(updateAllowedOrigins(origins));
const state = store.getState().config;
expect(state.api.extraOrigins).toBe(origins.join(', '));
});
test('setUpnpState updates upnp settings', async () => {
const { setUpnpState } = await import('@app/store/modules/config.js');
store.dispatch(setUpnpState({ enabled: 'yes', status: 'active' }));
const state = store.getState().config;
expect(state.remote.upnpEnabled).toBe('yes');
expect(state.connectionStatus.upnpStatus).toBe('active');
});
test('setWanPortToValue updates wanport', async () => {
const { setWanPortToValue } = await import('@app/store/modules/config.js');
store.dispatch(setWanPortToValue(8443));
const state = store.getState().config;
expect(state.remote.wanport).toBe('8443');
});
test('setWanAccess updates wanaccess', async () => {
const { setWanAccess } = await import('@app/store/modules/config.js');
store.dispatch(setWanAccess('yes'));
const state = store.getState().config;
expect(state.remote.wanaccess).toBe('yes');
});
// test('addSsoUser adds user to ssoSubIds', async () => {
// const { addSsoUser } = await import('@app/store/modules/config.js');
// store.dispatch(addSsoUser('user1'));
// store.dispatch(addSsoUser('user2'));
// const state = store.getState().config;
// expect(state.remote.ssoSubIds).toBe('user1,user2');
// });
// test('removeSsoUser removes user from ssoSubIds', async () => {
// const { addSsoUser, removeSsoUser } = await import('@app/store/modules/config.js');
// store.dispatch(addSsoUser('user1'));
// store.dispatch(addSsoUser('user2'));
// store.dispatch(removeSsoUser('user1'));
// const state = store.getState().config;
// expect(state.remote.ssoSubIds).toBe('user2');
// });
// test('removeSsoUser with null clears all ssoSubIds', async () => {
// const { addSsoUser, removeSsoUser } = await import('@app/store/modules/config.js');
// store.dispatch(addSsoUser('user1'));
// store.dispatch(addSsoUser('user2'));
// store.dispatch(removeSsoUser(null));
// const state = store.getState().config;
// expect(state.remote.ssoSubIds).toBe('');
// });
test('setLocalApiKey updates localApiKey', async () => {
const { setLocalApiKey } = await import('@app/store/modules/config.js');
store.dispatch(setLocalApiKey('new-local-api-key'));
const state = store.getState().config;
expect(state.remote.localApiKey).toBe('new-local-api-key');
});
test('setLocalApiKey with null clears localApiKey', async () => {
const { setLocalApiKey } = await import('@app/store/modules/config.js');
store.dispatch(setLocalApiKey(null));
const state = store.getState().config;
expect(state.remote.localApiKey).toBe('');
});
// test('setGraphqlConnectionStatus updates minigraph status', async () => {
// store.dispatch(setGraphqlConnectionStatus({ status: MinigraphStatus.CONNECTED, error: null }));
// const state = store.getState().config;
// expect(state.connectionStatus.minigraph).toBe(MinigraphStatus.CONNECTED);
// });
// test('setupRemoteAccessThunk.fulfilled updates remote access settings', async () => {
// const remoteAccessSettings = {
// accessType: WAN_ACCESS_TYPE.DYNAMIC,
// forwardType: WAN_FORWARD_TYPE.UPNP,
// };
// await store.dispatch(setupRemoteAccessThunk(remoteAccessSettings));
// const state = store.getState().config;
// expect(state.remote).toMatchObject({
// wanaccess: 'no',
// dynamicRemoteAccessType: 'UPNP',
// wanport: '',
// upnpEnabled: 'yes',
// });
// });
});

View File

@@ -4,32 +4,63 @@ import { store } from '@app/store/index.js';
test('Returns paths', async () => {
const { paths } = store.getState();
expect(Object.keys(paths)).toMatchInlineSnapshot(`
[
"core",
"unraid-api-base",
"unraid-data",
"docker-autostart",
"docker-socket",
"parity-checks",
"htpasswd",
"emhttpd-socket",
"states",
"dynamix-base",
"dynamix-config",
"myservers-base",
"myservers-config",
"myservers-config-states",
"myservers-env",
"myservers-keepalive",
"keyfile-base",
"machine-id",
"log-base",
"unraid-log-base",
"var-run",
"auth-sessions",
"auth-keys",
"libvirt-pid",
]
`);
expect(Object.keys(paths)).toMatchSnapshot();
expect(paths).toMatchObject({
core: expect.stringContaining('api/src/store/modules'),
'unraid-api-base': '/usr/local/unraid-api/',
'unraid-data': expect.stringContaining('api/dev/data'),
'docker-autostart': '/var/lib/docker/unraid-autostart',
'docker-socket': '/var/run/docker.sock',
'parity-checks': expect.stringContaining('api/dev/states/parity-checks.log'),
htpasswd: '/etc/nginx/htpasswd',
'emhttpd-socket': '/var/run/emhttpd.socket',
states: expect.stringContaining('api/dev/states'),
'dynamix-base': expect.stringContaining('api/dev/dynamix'),
'dynamix-config': expect.arrayContaining([
expect.stringContaining('api/dev/dynamix/default.cfg'),
expect.stringContaining('api/dev/dynamix/dynamix.cfg'),
]),
'myservers-base': '/boot/config/plugins/dynamix.my.servers/',
'myservers-config': expect.stringContaining('api/dev/Unraid.net/myservers.cfg'),
'myservers-config-states': expect.stringContaining('api/dev/states/myservers.cfg'),
'myservers-env': '/boot/config/plugins/dynamix.my.servers/env',
'myservers-keepalive': './dev/Unraid.net/fb_keepalive',
'keyfile-base': expect.stringContaining('api/dev/Unraid.net'),
'machine-id': expect.stringContaining('api/dev/data/machine-id'),
'log-base': '/var/log/unraid-api',
'unraid-log-base': '/var/log',
'var-run': '/var/run',
'auth-sessions': './dev/sessions',
'auth-keys': expect.stringContaining('api/dev/keys'),
passwd: expect.stringContaining('api/dev/passwd'),
'libvirt-pid': '/var/run/libvirt/libvirtd.pid',
activationBase: expect.stringContaining('api/dev/activation'),
webGuiBase: '/usr/local/emhttp/webGui',
identConfig: '/boot/config/ident.cfg',
activation: {
assets: expect.stringContaining('api/dev/activation/assets'),
logo: expect.stringContaining('api/dev/activation/assets/logo.svg'),
caseModel: expect.stringContaining('api/dev/activation/assets/case-model.png'),
banner: expect.stringContaining('api/dev/activation/assets/banner.png'),
},
boot: {
caseModel: expect.stringContaining('api/dev/dynamix/case-model.png'),
},
webgui: {
imagesBase: '/usr/local/emhttp/webGui/images',
logo: {
fullPath: '/usr/local/emhttp/webGui/images/UN-logotype-gradient.svg',
assetPath: '/webGui/images/UN-logotype-gradient.svg',
},
caseModel: {
fullPath: '/usr/local/emhttp/webGui/images/case-model.png',
assetPath: '/webGui/images/case-model.png',
},
banner: {
fullPath: '/usr/local/emhttp/webGui/images/banner.png',
assetPath: '/webGui/images/banner.png',
},
},
});
});

View File

@@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest';
import { csvStringToArray, formatDatetime } from '@app/utils.js';
import { csvStringToArray, formatDatetime, parsePackageArg } from '@app/utils.js';
describe('formatDatetime', () => {
const testDate = new Date('2024-02-14T12:34:56');
@@ -103,3 +103,78 @@ describe('csvStringToArray', () => {
expect(csvStringToArray(',one,')).toEqual(['one']);
});
});
describe('parsePackageArg', () => {
it('parses simple package names without version', () => {
expect(parsePackageArg('lodash')).toEqual({ name: 'lodash' });
expect(parsePackageArg('express')).toEqual({ name: 'express' });
expect(parsePackageArg('react')).toEqual({ name: 'react' });
});
it('parses simple package names with version', () => {
expect(parsePackageArg('lodash@4.17.21')).toEqual({ name: 'lodash', version: '4.17.21' });
expect(parsePackageArg('express@4.18.2')).toEqual({ name: 'express', version: '4.18.2' });
expect(parsePackageArg('react@18.2.0')).toEqual({ name: 'react', version: '18.2.0' });
});
it('parses scoped package names without version', () => {
expect(parsePackageArg('@types/node')).toEqual({ name: '@types/node' });
expect(parsePackageArg('@angular/core')).toEqual({ name: '@angular/core' });
expect(parsePackageArg('@nestjs/common')).toEqual({ name: '@nestjs/common' });
});
it('parses scoped package names with version', () => {
expect(parsePackageArg('@types/node@18.15.0')).toEqual({
name: '@types/node',
version: '18.15.0',
});
expect(parsePackageArg('@angular/core@15.2.0')).toEqual({
name: '@angular/core',
version: '15.2.0',
});
expect(parsePackageArg('@nestjs/common@9.3.12')).toEqual({
name: '@nestjs/common',
version: '9.3.12',
});
});
it('handles version ranges and tags', () => {
expect(parsePackageArg('lodash@^4.17.0')).toEqual({ name: 'lodash', version: '^4.17.0' });
expect(parsePackageArg('react@~18.2.0')).toEqual({ name: 'react', version: '~18.2.0' });
expect(parsePackageArg('express@latest')).toEqual({ name: 'express', version: 'latest' });
expect(parsePackageArg('vue@beta')).toEqual({ name: 'vue', version: 'beta' });
expect(parsePackageArg('@types/node@next')).toEqual({ name: '@types/node', version: 'next' });
});
it('handles multiple @ symbols correctly', () => {
expect(parsePackageArg('package@1.0.0@extra')).toEqual({
name: 'package@1.0.0',
version: 'extra',
});
expect(parsePackageArg('@scope/pkg@1.0.0@extra')).toEqual({
name: '@scope/pkg@1.0.0',
version: 'extra',
});
});
it('ignores versions that contain forward slashes', () => {
expect(parsePackageArg('package@github:user/repo')).toEqual({
name: 'package@github:user/repo',
});
expect(parsePackageArg('@scope/pkg@git+https://github.com/user/repo.git')).toEqual({
name: '@scope/pkg@git+https://github.com/user/repo.git',
});
});
it('handles edge cases', () => {
expect(parsePackageArg('@')).toEqual({ name: '@' });
expect(parsePackageArg('@scope')).toEqual({ name: '@scope' });
expect(parsePackageArg('package@')).toEqual({ name: 'package@' });
expect(parsePackageArg('@scope/pkg@')).toEqual({ name: '@scope/pkg@' });
});
it('handles empty version strings', () => {
expect(parsePackageArg('package@')).toEqual({ name: 'package@' });
expect(parsePackageArg('@scope/package@')).toEqual({ name: '@scope/package@' });
});
});

View File

@@ -20,6 +20,7 @@ const getUnraidApiLocation = async () => {
};
try {
await import('json-bigint-patch');
await CommandFactory.run(CliModule, {
cliName: 'unraid-api',
logger: LOG_LEVEL === 'TRACE' ? new LogService() : false, // - enable this to see nest initialization issues

View File

@@ -1,4 +1,3 @@
import { getters } from '@app/store/index.js';
import { FileLoadStatus } from '@app/store/types.js';
/**
@@ -6,6 +5,7 @@ import { FileLoadStatus } from '@app/store/types.js';
* @returns The current version.
*/
export const getUnraidVersion = async (): Promise<string> => {
const { getters } = await import('@app/store/index.js');
const { status, var: emhttpVar } = getters.emhttp();
if (status === FileLoadStatus.LOADED) {
return emhttpVar.version;

View File

@@ -79,6 +79,3 @@ export const KEYSERVER_VALIDATION_ENDPOINT = 'https://keys.lime-technology.com/v
/** Set the max retries for the GraphQL Client */
export const MAX_RETRIES_FOR_LINEAR_BACKOFF = 100;
export const PM2_PATH = join(import.meta.dirname, '../../', 'node_modules', 'pm2', 'bin', 'pm2');
export const ECOSYSTEM_PATH = join(import.meta.dirname, '../../', 'ecosystem.config.json');

View File

@@ -1,18 +1,15 @@
import { pino } from 'pino';
import pretty from 'pino-pretty';
import { LOG_TYPE } from '@app/environment.js';
import { API_VERSION, LOG_LEVEL, LOG_TYPE } from '@app/environment.js';
export const levels = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'] as const;
export type LogLevel = (typeof levels)[number];
const level =
levels[levels.indexOf(process.env.LOG_LEVEL?.toLowerCase() as (typeof levels)[number])] ?? 'info';
const level = levels[levels.indexOf(LOG_LEVEL.toLowerCase() as LogLevel)] ?? 'info';
export const logDestination = pino.destination({
sync: true,
});
export const logDestination = pino.destination();
const stream =
LOG_TYPE === 'pretty'
@@ -28,9 +25,30 @@ const stream =
export const logger = pino(
{
level,
timestamp: () => `,"time":"${new Date().toISOString()}"`,
timestamp: pino.stdTimeFunctions.isoTime,
formatters: {
level: (label: string) => ({ level: label }),
bindings: (bindings) => ({ ...bindings, apiVersion: API_VERSION }),
},
redact: {
paths: [
'*.password',
'*.pass',
'*.secret',
'*.token',
'*.key',
'*.Password',
'*.Pass',
'*.Secret',
'*.Token',
'*.Key',
'*.apikey',
'*.localApiKey',
'*.accesstoken',
'*.idtoken',
'*.refreshtoken',
],
censor: '***REDACTED***',
},
},
stream
@@ -71,3 +89,19 @@ export const loggers = [
remoteQueryLogger,
apiLogger,
];
export function sanitizeParams(params: Record<string, any>): Record<string, any> {
const SENSITIVE_KEYS = ['password', 'secret', 'token', 'key', 'client_secret'];
const mask = (value: any) => (typeof value === 'string' && value.length > 0 ? '***' : value);
const sanitized: Record<string, any> = {};
for (const k in params) {
if (SENSITIVE_KEYS.some((s) => k.toLowerCase().includes(s))) {
sanitized[k] = mask(params[k]);
} else if (typeof params[k] === 'object' && params[k] !== null && !Array.isArray(params[k])) {
sanitized[k] = sanitizeParams(params[k]);
} else {
sanitized[k] = params[k];
}
}
return sanitized;
}

View File

@@ -1,26 +1,13 @@
import EventEmitter from 'events';
import { GRAPHQL_PUBSUB_CHANNEL } from '@unraid/shared/pubsub/graphql.pubsub.js';
import { PubSub } from 'graphql-subscriptions';
// Allow subscriptions to have 30 connections
const eventEmitter = new EventEmitter();
eventEmitter.setMaxListeners(30);
export enum PUBSUB_CHANNEL {
ARRAY = 'ARRAY',
DASHBOARD = 'DASHBOARD',
DISPLAY = 'DISPLAY',
INFO = 'INFO',
NOTIFICATION = 'NOTIFICATION',
NOTIFICATION_ADDED = 'NOTIFICATION_ADDED',
NOTIFICATION_OVERVIEW = 'NOTIFICATION_OVERVIEW',
OWNER = 'OWNER',
SERVERS = 'SERVERS',
VMS = 'VMS',
REGISTRATION = 'REGISTRATION',
LOG_FILE = 'LOG_FILE',
PARITY = 'PARITY',
}
export { GRAPHQL_PUBSUB_CHANNEL as PUBSUB_CHANNEL };
export const pubsub = new PubSub({ eventEmitter });
@@ -28,6 +15,6 @@ export const pubsub = new PubSub({ eventEmitter });
* Create a pubsub subscription.
* @param channel The pubsub channel to subscribe to.
*/
export const createSubscription = (channel: PUBSUB_CHANNEL) => {
export const createSubscription = (channel: GRAPHQL_PUBSUB_CHANNEL) => {
return pubsub.asyncIterableIterator(channel);
};

View File

@@ -23,6 +23,9 @@ interface Display {
scale: string;
tabs: string;
text: string;
/**
* 'black' or 'white' or 'azure' or 'gray'
*/
theme: string;
total: string;
unit: Unit;
@@ -30,6 +33,32 @@ interface Display {
warning: string;
wwn: string;
locale: string;
/**
* hex color (without #)
*/
headerMetaColor: string;
/**
* 'yes' or 'no'
*/
showBannerGradient: string;
/**
* 'yes' or 'no'
*/
headerdescription: string;
/**
* Header Secondary Text Color (without #)
*/
headermetacolor: string;
/**
* Header Text Color (without #)
*/
header: string;
/**
* Header Background Color (without #)
*/
background: string;
tty: string;
raw: string;
}
/**

View File

@@ -1,41 +1,76 @@
import { got } from 'got';
import retry from 'p-retry';
import { AppError } from '@app/core/errors/app-error.js';
import { logger } from '@app/core/log.js';
import { type LooseObject } from '@app/core/types/index.js';
import { DRY_RUN } from '@app/environment.js';
import { getters } from '@app/store/index.js';
import { appLogger } from '@app/core/log.js';
import { LooseObject } from '@app/core/types/global.js';
import { store } from '@app/store/index.js';
import { loadSingleStateFile } from '@app/store/modules/emhttp.js';
import { StateFileKey } from '@app/store/types.js';
/**
* Run a command with emcmd.
*/
export const emcmd = async (commands: LooseObject) => {
export const emcmd = async (
commands: LooseObject,
{ waitForToken = false }: { waitForToken?: boolean } = {}
) => {
const { getters } = await import('@app/store/index.js');
const socketPath = getters.paths()['emhttpd-socket'];
const { csrfToken } = getters.emhttp().var;
const url = `http://unix:${socketPath}:/update.htm`;
const options = {
qs: {
...commands,
csrf_token: csrfToken,
},
};
if (DRY_RUN) {
logger.debug(url, options);
// Ensure we only log on dry-run
return;
if (!socketPath) {
appLogger.error('No emhttpd socket path found');
throw new AppError('No emhttpd socket path found');
}
return got
.get(url, {
enableUnixSockets: true,
searchParams: { ...commands, csrf_token: csrfToken },
})
.catch((error: NodeJS.ErrnoException) => {
if (error.code === 'ENOENT') {
throw new AppError('emhttpd socket unavailable.');
let { csrfToken } = getters.emhttp().var;
if (!csrfToken && waitForToken) {
csrfToken = await retry(
async (retries) => {
if (retries > 1) {
appLogger.info('Waiting for CSRF token...');
}
const loadedState = await store.dispatch(loadSingleStateFile(StateFileKey.var)).unwrap();
let token: string | undefined;
if (loadedState && 'var' in loadedState) {
token = loadedState.var.csrfToken;
}
if (!token) {
throw new Error('CSRF token not found yet');
}
return token;
},
{
minTimeout: 5000,
maxTimeout: 10000,
retries: 10,
}
throw error;
).catch((error) => {
appLogger.error('Failed to load CSRF token after multiple retries', error);
throw new AppError('Failed to load CSRF token after multiple retries');
});
}
appLogger.debug(`Executing emcmd with commands: ${JSON.stringify(commands)}`);
try {
const paramsObj = { ...commands, csrf_token: csrfToken };
const params = new URLSearchParams(paramsObj);
const response = await got.get(`http://unix:${socketPath}:/update.htm`, {
enableUnixSockets: true,
searchParams: params,
});
appLogger.debug('emcmd executed successfully');
return response;
} catch (error: any) {
if (error.code === 'ENOENT') {
appLogger.error('emhttpd socket unavailable.', error);
throw new Error('emhttpd socket unavailable.');
}
appLogger.error(`emcmd execution failed: ${error.message}`, error);
throw error;
}
};

View File

@@ -124,7 +124,15 @@ export const parseConfig = <T extends Record<string, any>>(
throw new AppError('Invalid Parameters Passed to ParseConfig');
}
const data: Record<string, any> = parseIni(fileContents);
let data: Record<string, any>;
try {
data = parseIni(fileContents);
} catch (error) {
throw new AppError(
`Failed to parse config file: ${error instanceof Error ? error.message : String(error)}`
);
}
// Remove quotes around keys
const dataWithoutQuoteKeys = Object.fromEntries(
Object.entries(data).map(([key, value]) => [key.replace(/^"(.+(?="$))"$/, '$1'), value])

View File

@@ -0,0 +1,21 @@
import { execa } from 'execa';
import { internalLogger } from '@app/core/log.js';
/**
* Check if Unraid is in GUI mode by looking for the slim process.
* @returns true if Unraid is in GUI mode, false otherwise.
*/
const isGuiMode = async (): Promise<boolean> => {
try {
// Use pgrep to check if slim process is running
const { exitCode } = await execa('pgrep', ['slim'], { reject: false });
// exitCode 0 means process was found, 1 means not found
return exitCode === 0;
} catch (error) {
internalLogger.error('Error checking GUI mode: %s', error);
return false;
}
};
export default isGuiMode;

View File

@@ -9,6 +9,8 @@ const env =
override: true,
})
: config({
debug: false,
quiet: true,
path: '/usr/local/unraid-api/.env',
encoding: 'utf-8',
});

View File

@@ -1,3 +1,6 @@
// Defines environment & configuration constants.
// Non-function exports from this module are loaded into the NestJS Config at runtime.
import { readFileSync } from 'node:fs';
import { homedir } from 'node:os';
import { join } from 'node:path';
@@ -78,7 +81,6 @@ export const ENVIRONMENT = process.env.ENVIRONMENT
: 'production';
export const GRAPHQL_INTROSPECTION = Boolean(INTROSPECTION ?? DEBUG ?? ENVIRONMENT !== 'production');
export const PORT = process.env.PORT ?? '/var/run/unraid-api.sock';
export const DRY_RUN = process.env.DRY_RUN === 'true';
export const BYPASS_PERMISSION_CHECKS = process.env.BYPASS_PERMISSION_CHECKS === 'true';
export const BYPASS_CORS_CHECKS = process.env.BYPASS_CORS_CHECKS === 'true';
export const LOG_CORS = process.env.LOG_CORS === 'true';
@@ -95,4 +97,9 @@ export const MOTHERSHIP_GRAPHQL_LINK = process.env.MOTHERSHIP_GRAPHQL_LINK
: 'https://mothership.unraid.net/ws';
export const PM2_HOME = process.env.PM2_HOME ?? join(homedir(), '.pm2');
export const PATHS_CONFIG_MODULES = process.env.PATHS_CONFIG_MODULES!;
export const PM2_PATH = join(import.meta.dirname, '../../', 'node_modules', 'pm2', 'bin', 'pm2');
export const ECOSYSTEM_PATH = join(import.meta.dirname, '../../', 'ecosystem.config.json');
export const LOGS_DIR = process.env.LOGS_DIR ?? '/var/log/unraid-api';
export const PATHS_CONFIG_MODULES =
process.env.PATHS_CONFIG_MODULES ?? '/boot/config/plugins/dynamix.my.servers/configs';

View File

@@ -1,35 +0,0 @@
import type { ASTNode } from 'graphql';
import { GraphQLScalarType } from 'graphql';
import { Kind } from 'graphql/language/index.js';
const MAX_LONG = Number.MAX_SAFE_INTEGER;
const MIN_LONG = Number.MIN_SAFE_INTEGER;
const coerceLong = (value) => {
if (value === '')
throw new TypeError('Long cannot represent non 52-bit signed integer value: (empty string)');
const num = Number(value);
if (num == num && num <= MAX_LONG && num >= MIN_LONG) {
if (num < 0) {
return Math.ceil(num);
}
return Math.floor(num);
}
throw new TypeError('Long cannot represent non 52-bit signed integer value: ' + String(value));
};
const parseLiteral = (ast: ASTNode) => {
if (ast.kind === Kind.INT) {
const num = parseInt(ast.value, 10);
if (num <= MAX_LONG && num >= MIN_LONG) return num;
}
return null;
};
export const GraphQLLong = new GraphQLScalarType({
name: 'Long',
description: 'The `Long` scalar type represents 52-bit integers',
serialize: coerceLong,
parseValue: coerceLong,
parseLiteral: parseLiteral,
});

View File

@@ -1,7 +0,0 @@
import { logger } from '@app/core/log.js';
import { type ApiKeyResponse } from '@app/unraid-api/graph/resolvers/cloud/cloud.model.js';
export const checkApi = async (): Promise<ApiKeyResponse> => {
logger.trace('Cloud endpoint: Checking API');
return { valid: true };
};

View File

@@ -1,104 +0,0 @@
import { got } from 'got';
import { FIVE_DAYS_SECS, ONE_DAY_SECS } from '@app/consts.js';
import { logger } from '@app/core/log.js';
import { API_VERSION, MOTHERSHIP_GRAPHQL_LINK } from '@app/environment.js';
import { checkDNS } from '@app/graphql/resolvers/query/cloud/check-dns.js';
import { checkMothershipAuthentication } from '@app/graphql/resolvers/query/cloud/check-mothership-authentication.js';
import { getCloudCache, getDnsCache } from '@app/store/getters/index.js';
import { getters, store } from '@app/store/index.js';
import { setCloudCheck, setDNSCheck } from '@app/store/modules/cache.js';
import { CloudResponse, MinigraphStatus } from '@app/unraid-api/graph/resolvers/cloud/cloud.model.js';
const mothershipBaseUrl = new URL(MOTHERSHIP_GRAPHQL_LINK).origin;
const createGotOptions = (apiVersion: string, apiKey: string) => ({
timeout: {
request: 5_000,
},
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
'x-unraid-api-version': apiVersion,
'x-api-key': apiKey,
},
});
/**
* This is mainly testing the user's network config
* If they cannot resolve this they may have it blocked or have a routing issue
*/
const checkCanReachMothership = async (apiVersion: string, apiKey: string): Promise<void> => {
const mothershipCanBeResolved = await got
.head(mothershipBaseUrl, createGotOptions(apiVersion, apiKey))
.then(() => true)
.catch(() => false);
if (!mothershipCanBeResolved) throw new Error(`Unable to connect to ${mothershipBaseUrl}`);
};
/**
* Run a more performant cloud check with permanent DNS checking
*/
const fastCloudCheck = async (): Promise<CloudResponse> => {
const result = { status: 'ok', error: null, ip: 'FAST_CHECK_NO_IP_FOUND' };
const cloudIp = getDnsCache()?.cloudIp ?? null;
if (cloudIp) {
result.ip = cloudIp;
} else {
try {
result.ip = (await checkDNS()).cloudIp;
logger.debug('DNS_CHECK_RESULT', await checkDNS());
store.dispatch(setDNSCheck({ cloudIp: result.ip, ttl: FIVE_DAYS_SECS, error: null }));
} catch (error: unknown) {
logger.warn('Failed to fetch DNS, but Minigraph is connected - continuing');
result.ip = `ERROR: ${error instanceof Error ? error.message : 'Unknown Error'}`;
// Don't set an error since we're actually connected to the cloud
store.dispatch(setDNSCheck({ cloudIp: result.ip, ttl: ONE_DAY_SECS, error: null }));
}
}
return result;
};
export const checkCloud = async (): Promise<CloudResponse> => {
logger.trace('Cloud endpoint: Checking mothership');
try {
const config = getters.config();
const apiVersion = API_VERSION;
const apiKey = config.remote.apikey;
const graphqlStatus = getters.minigraph().status;
const result = { status: 'ok', error: null, ip: 'NO_IP_FOUND' };
// If minigraph is connected, skip the follow cloud checks
if (graphqlStatus === MinigraphStatus.CONNECTED) {
return await fastCloudCheck();
}
// Check GraphQL Conneciton State, if it's broken, run these checks
if (!apiKey) throw new Error('API key is missing');
const oldCheckResult = getCloudCache();
if (oldCheckResult) {
logger.trace('Using cached result for cloud check', oldCheckResult);
return oldCheckResult;
}
// Check DNS
result.ip = (await checkDNS()).cloudIp;
// Check if we can reach mothership
await checkCanReachMothership(apiVersion, apiKey);
// Check auth, rate limiting, etc.
await checkMothershipAuthentication(apiVersion, apiKey);
// Cache for 10 minutes
store.dispatch(setCloudCheck(result));
return result;
} catch (error: unknown) {
if (!(error instanceof Error)) throw new Error(`Unknown Error "${error as string}"`);
return { status: 'error', error: error.message };
}
};

View File

@@ -1,70 +0,0 @@
import { lookup as lookupDNS, resolve as resolveDNS } from 'dns';
import { promisify } from 'util';
import ip from 'ip';
import { MOTHERSHIP_GRAPHQL_LINK } from '@app/environment.js';
import { getDnsCache } from '@app/store/getters/index.js';
import { store } from '@app/store/index.js';
import { setDNSCheck } from '@app/store/modules/cache.js';
const msHostname = new URL(MOTHERSHIP_GRAPHQL_LINK).host;
/**
* Check if the local and network resolvers are able to see mothership
*
* See: https://nodejs.org/docs/latest/api/dns.html#dns_implementation_considerations
*/
export const checkDNS = async (hostname = msHostname): Promise<{ cloudIp: string }> => {
const dnsCachedResuslt = getDnsCache();
if (dnsCachedResuslt) {
if (dnsCachedResuslt.cloudIp) {
return { cloudIp: dnsCachedResuslt.cloudIp };
}
if (dnsCachedResuslt.error) {
throw dnsCachedResuslt.error;
}
}
let local: string | null = null;
let network: string | null = null;
try {
// Check the local resolver like "ping" does
// Check the DNS server the server has set - does a DNS query on the network
const [localRes, networkRes] = await Promise.all([
promisify(lookupDNS)(hostname).then(({ address }) => address),
promisify(resolveDNS)(hostname).then(([address]) => address),
]);
local = localRes;
network = networkRes;
// The user's server and the DNS server they're using are returning different results
if (!local.includes(network))
throw new Error(
`Local and network resolvers showing different IP for "${hostname}". [local="${
local ?? 'NOT FOUND'
}"] [network="${network ?? 'NOT FOUND'}"]`
);
// The user likely has a PI-hole or something similar running.
if (ip.isPrivate(local))
throw new Error(
`"${hostname}" is being resolved to a private IP. [IP=${local ?? 'NOT FOUND'}]`
);
} catch (error: unknown) {
if (!(error instanceof Error)) {
throw error;
}
store.dispatch(setDNSCheck({ cloudIp: null, error }));
}
if (typeof local === 'string' || typeof network === 'string') {
const validIp: string = local ?? network ?? '';
store.dispatch(setDNSCheck({ cloudIp: validIp, error: null }));
return { cloudIp: validIp };
}
return { cloudIp: '' };
};

View File

@@ -1,13 +0,0 @@
import { logger } from '@app/core/log.js';
import { getters } from '@app/store/index.js';
import { MinigraphqlResponse } from '@app/unraid-api/graph/resolvers/cloud/cloud.model.js';
export const checkMinigraphql = (): MinigraphqlResponse => {
logger.trace('Cloud endpoint: Checking mini-graphql');
// Do we have a connection to mothership?
const { status, error, timeout, timeoutStart } = getters.minigraph();
const timeoutRemaining = timeout && timeoutStart ? timeout - (Date.now() - timeoutStart) : null;
return { status, error, timeout: timeoutRemaining };
};

View File

@@ -1,61 +0,0 @@
import { got, HTTPError, TimeoutError } from 'got';
import { logger } from '@app/core/log.js';
import { MOTHERSHIP_GRAPHQL_LINK } from '@app/environment.js';
const createGotOptions = (apiVersion: string, apiKey: string) => ({
timeout: {
request: 5_000,
},
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
'x-unraid-api-version': apiVersion,
'x-api-key': apiKey,
},
});
const isHttpError = (error: unknown): error is HTTPError => error instanceof HTTPError;
// Check if we're rate limited, etc.
export const checkMothershipAuthentication = async (apiVersion: string, apiKey: string) => {
const msURL = new URL(MOTHERSHIP_GRAPHQL_LINK);
const url = `https://${msURL.hostname}${msURL.pathname}`;
try {
const options = createGotOptions(apiVersion, apiKey);
// This will throw if there is a non 2XX/3XX code
await got.head(url, options);
} catch (error: unknown) {
// HTTP errors
if (isHttpError(error)) {
switch (error.response.statusCode) {
case 429: {
const retryAfter = error.response.headers['retry-after'];
throw new Error(
retryAfter
? `${url} is rate limited for another ${retryAfter} seconds`
: `${url} is rate limited`
);
}
case 401:
throw new Error('Invalid credentials');
default:
throw new Error(
`Failed to connect to ${url} with a "${error.response.statusCode}" HTTP error.`
);
}
}
// Timeout error
if (error instanceof TimeoutError) throw new Error(`Timed-out while connecting to "${url}"`);
// Unknown error
logger.trace('Unknown Error', error);
// @TODO: Add in the cause when we move to a newer node version
// throw new Error('Unknown Error', { cause: error as Error });
throw new Error('Unknown Error');
}
};

View File

@@ -1,14 +0,0 @@
export type Cloud = {
error: string | null;
apiKey: { valid: true; error: null } | { valid: false; error: string };
minigraphql: {
status: 'connected' | 'disconnected';
};
cloud: { status: 'ok'; error: null; ip: string } | { status: 'error'; error: string };
allowedOrigins: string[];
};
export const createResponse = (cloud: Omit<Cloud, 'error'>): Cloud => ({
...cloud,
error: cloud.apiKey.error ?? cloud.cloud.error,
});

View File

@@ -1,423 +0,0 @@
import { access } from 'fs/promises';
import toBytes from 'bytes';
import { execa, execaCommandSync } from 'execa';
import { isSymlink } from 'path-type';
import { cpu, cpuFlags, mem, memLayout, osInfo, versions } from 'systeminformation';
import type { PciDevice } from '@app/core/types/index.js';
import { bootTimestamp } from '@app/common/dashboard/boot-timestamp.js';
import { getUnraidVersion } from '@app/common/dashboard/get-unraid-version.js';
import { AppError } from '@app/core/errors/app-error.js';
import { type DynamixConfig } from '@app/core/types/ini.js';
import { toBoolean } from '@app/core/utils/casting.js';
import { docker } from '@app/core/utils/clients/docker.js';
import { cleanStdout } from '@app/core/utils/misc/clean-stdout.js';
import { loadState } from '@app/core/utils/misc/load-state.js';
import { sanitizeProduct } from '@app/core/utils/vms/domain/sanitize-product.js';
import { sanitizeVendor } from '@app/core/utils/vms/domain/sanitize-vendor.js';
import { vmRegExps } from '@app/core/utils/vms/domain/vm-regexps.js';
import { filterDevices } from '@app/core/utils/vms/filter-devices.js';
import { getPciDevices } from '@app/core/utils/vms/get-pci-devices.js';
import { getters } from '@app/store/index.js';
import {
Devices,
Display,
Gpu,
InfoApps,
InfoCpu,
InfoMemory,
Os as InfoOs,
MemoryLayout,
Temperature,
Theme,
Versions,
} from '@app/unraid-api/graph/resolvers/info/info.model.js';
export const generateApps = async (): Promise<InfoApps> => {
const installed = await docker
.listContainers({ all: true })
.catch(() => [])
.then((containers) => containers.length);
const started = await docker
.listContainers()
.catch(() => [])
.then((containers) => containers.length);
return { id: 'info/apps', installed, started };
};
export const generateOs = async (): Promise<InfoOs> => {
const os = await osInfo();
return {
id: 'info/os',
...os,
hostname: getters.emhttp().var.name,
uptime: bootTimestamp.toISOString(),
};
};
export const generateCpu = async (): Promise<InfoCpu> => {
const { cores, physicalCores, speedMin, speedMax, stepping, ...rest } = await cpu();
const flags = await cpuFlags()
.then((flags) => flags.split(' '))
.catch(() => []);
return {
id: 'info/cpu',
...rest,
cores: physicalCores,
threads: cores,
flags,
stepping: Number(stepping),
// @TODO Find out what these should be if they're not defined
speedmin: speedMin || -1,
speedmax: speedMax || -1,
};
};
export const generateDisplay = async (): Promise<Display> => {
const filePaths = getters.paths()['dynamix-config'];
const state = filePaths.reduce<Partial<DynamixConfig>>(
(acc, filePath) => {
const state = loadState<DynamixConfig>(filePath);
return state ? { ...acc, ...state } : acc;
},
{
id: 'dynamix-config/display',
}
);
if (!state.display) {
return {
id: 'dynamix-config/display',
};
}
const { theme, unit, ...display } = state.display;
return {
id: 'dynamix-config/display',
...display,
theme: theme as Theme,
unit: unit as Temperature,
scale: toBoolean(display.scale),
tabs: toBoolean(display.tabs),
resize: toBoolean(display.resize),
wwn: toBoolean(display.wwn),
total: toBoolean(display.total),
usage: toBoolean(display.usage),
text: toBoolean(display.text),
warning: Number.parseInt(display.warning, 10),
critical: Number.parseInt(display.critical, 10),
hot: Number.parseInt(display.hot, 10),
max: Number.parseInt(display.max, 10),
locale: display.locale || 'en_US',
};
};
export const generateVersions = async (): Promise<Versions> => {
const unraid = await getUnraidVersion();
const softwareVersions = await versions();
return {
id: 'info/versions',
unraid,
...softwareVersions,
};
};
export const generateMemory = async (): Promise<InfoMemory> => {
const layout = await memLayout()
.then((dims) => dims.map((dim) => dim as MemoryLayout))
.catch(() => []);
const info = await mem();
let max = info.total;
// Max memory
try {
const memoryInfo = await execa('dmidecode', ['-t', 'memory'])
.then(cleanStdout)
.catch((error: NodeJS.ErrnoException) => {
if (error.code === 'ENOENT') {
throw new AppError('The dmidecode cli utility is missing.');
}
throw error;
});
const lines = memoryInfo.split('\n');
const header = lines.find((line) => line.startsWith('Physical Memory Array'));
if (header) {
const start = lines.indexOf(header);
const nextHeaders = lines.slice(start, -1).find((line) => line.startsWith('Handle '));
if (nextHeaders) {
const end = lines.indexOf(nextHeaders);
const fields = lines.slice(start, end);
max =
toBytes(
fields
?.find((line) => line.trim().startsWith('Maximum Capacity'))
?.trim()
?.split(': ')[1] ?? '0'
) ?? 0;
}
}
} catch {
// Ignore errors here
}
return {
id: 'info/memory',
layout,
max,
...info,
};
};
export const generateDevices = async (): Promise<Devices> => {
/**
* Set device class to device.
* @param device The device to modify.
* @returns The same device passed in but with the class modified.
*/
const addDeviceClass = (device: Readonly<PciDevice>): PciDevice => {
const modifiedDevice: PciDevice = {
...device,
class: 'other',
};
// GPU
if (vmRegExps.allowedGpuClassId.test(device.typeid)) {
modifiedDevice.class = 'vga';
// Specialized product name cleanup for GPU
// GF116 [GeForce GTX 550 Ti] --> GeForce GTX 550 Ti
const regex = new RegExp(/.+\[(?<gpuName>.+)]/);
const productName = regex.exec(device.productname)?.groups?.gpuName;
if (productName) {
modifiedDevice.productname = productName;
}
return modifiedDevice;
// Audio
}
if (vmRegExps.allowedAudioClassId.test(device.typeid)) {
modifiedDevice.class = 'audio';
return modifiedDevice;
}
return modifiedDevice;
};
/**
* System PCI devices.
*/
const systemPciDevices = async (): Promise<PciDevice[]> => {
const devices = await getPciDevices();
const basePath = '/sys/bus/pci/devices/0000:';
// Remove devices with no IOMMU support
const filteredDevices = await Promise.all(
devices.map(async (device: Readonly<PciDevice>) => {
const exists = await access(`${basePath}${device.id}/iommu_group/`)
.then(() => true)
.catch(() => false);
return exists ? device : null;
})
).then((devices) => devices.filter((device) => device !== null));
/**
* Run device cleanup
*
* Tasks:
* - Mark disallowed devices
* - Add class
* - Add whether kernel-bound driver exists
* - Cleanup device vendor/product names
*/
const processedDevices = await filterDevices(filteredDevices).then(async (devices) =>
Promise.all(
devices
.map((device) => addDeviceClass(device as PciDevice))
.map(async (device) => {
// Attempt to get the current kernel-bound driver for this pci device
await isSymlink(`${basePath}${device.id}/driver`).then((symlink) => {
if (symlink) {
// $strLink = @readlink('/sys/bus/pci/devices/0000:'.$arrMatch['id']. '/driver');
// if (!empty($strLink)) {
// $strDriver = basename($strLink);
// }
}
});
// Clean up the vendor and product name
device.vendorname = sanitizeVendor(device.vendorname);
device.productname = sanitizeProduct(device.productname);
return device;
})
)
);
return processedDevices;
};
/**
* System GPU Devices
*
* @name systemGPUDevices
* @ignore
* @private
*/
const systemGPUDevices: Promise<Gpu[]> = systemPciDevices()
.then((devices) => {
return devices
.filter((device) => device.class === 'vga' && !device.allowed)
.map((entry) => {
const gpu: Gpu = {
blacklisted: entry.allowed,
class: entry.class,
id: entry.id,
productid: entry.product,
typeid: entry.typeid,
type: entry.manufacturer,
vendorname: entry.vendorname,
};
return gpu;
});
})
.catch(() => []);
/**
* System usb devices.
* @returns Array of USB devices.
*/
const getSystemUSBDevices = async () => {
try {
// Get a list of all usb hubs so we can filter the allowed/disallowed
const usbHubs = await execa('cat /sys/bus/usb/drivers/hub/*/modalias', { shell: true })
.then(({ stdout }) =>
stdout.split('\n').map((line) => {
const [, id] = line.match(/usb:v(\w{9})/) ?? [];
return id.replace('p', ':');
})
)
.catch(() => [] as string[]);
const emhttp = getters.emhttp();
// Remove boot drive
const filterBootDrive = (device: Readonly<PciDevice>): boolean =>
emhttp.var.flashGuid !== device.guid;
// Remove usb hubs
const filterUsbHubs = (device: Readonly<PciDevice>): boolean => !usbHubs.includes(device.id);
// Clean up the name
const sanitizeVendorName = (device: Readonly<PciDevice>) => {
const vendorname = sanitizeVendor(device.vendorname || '');
return {
...device,
vendorname,
};
};
const parseDeviceLine = (line: Readonly<string>): { value: string; string: string } => {
const emptyLine = { value: '', string: '' };
// If the line is blank return nothing
if (!line) {
return emptyLine;
}
// Parse the line
const [, _] = line.split(/[ \t]{2,}/).filter(Boolean);
const match = _.match(/^(\S+)\s(.*)/)?.slice(1);
// If there's no match return nothing
if (!match) {
return emptyLine;
}
return {
value: match[0],
string: match[1],
};
};
// Add extra fields to device
const parseDevice = (device: Readonly<PciDevice>) => {
const modifiedDevice: PciDevice = {
...device,
};
const info = execaCommandSync(`lsusb -d ${device.id} -v`).stdout.split('\n');
const deviceName = device.name.trim();
const iSerial = parseDeviceLine(info.filter((line) => line.includes('iSerial'))[0]);
const iProduct = parseDeviceLine(info.filter((line) => line.includes('iProduct'))[0]);
const iManufacturer = parseDeviceLine(
info.filter((line) => line.includes('iManufacturer'))[0]
);
const idProduct = parseDeviceLine(info.filter((line) => line.includes('idProduct'))[0]);
const idVendor = parseDeviceLine(info.filter((line) => line.includes('idVendor'))[0]);
const serial = `${iSerial.string.slice(8).slice(0, 4)}-${iSerial.string
.slice(8)
.slice(4)}`;
const guid = `${idVendor.value.slice(2)}-${idProduct.value.slice(2)}-${serial}`;
modifiedDevice.serial = iSerial.string;
modifiedDevice.product = iProduct.string;
modifiedDevice.manufacturer = iManufacturer.string;
modifiedDevice.guid = guid;
// Set name if missing
if (deviceName === '') {
modifiedDevice.name = `${iProduct.string} ${iManufacturer.string}`.trim();
}
// Name still blank? Replace using fallback default
if (deviceName === '') {
modifiedDevice.name = '[unnamed device]';
}
// Ensure name is trimmed
modifiedDevice.name = device.name.trim();
return modifiedDevice;
};
const parseUsbDevices = (stdout: string) =>
stdout.split('\n').map((line) => {
const regex = new RegExp(/^.+: ID (?<id>\S+)(?<name>.*)$/);
const result = regex.exec(line);
return result?.groups as unknown as PciDevice;
}) ?? [];
// Get all usb devices
const usbDevices = await execa('lsusb')
.then(async ({ stdout }) =>
parseUsbDevices(stdout)
.map(parseDevice)
.filter(filterBootDrive)
.filter(filterUsbHubs)
.map(sanitizeVendorName)
)
.catch(() => []);
return usbDevices;
} catch (error: unknown) {
return [];
}
};
return {
id: 'info/devices',
// Scsi: await scsiDevices,
gpu: await systemGPUDevices,
pci: await systemPciDevices(),
usb: await getSystemUSBDevices(),
};
};

View File

@@ -1,8 +1,9 @@
import { AccessUrl, URL_TYPE } from '@unraid/shared/network.model.js';
import type { RootState } from '@app/store/index.js';
import { logger } from '@app/core/log.js';
import { type Nginx } from '@app/core/types/states/nginx.js';
import { store } from '@app/store/index.js';
import { AccessUrl, URL_TYPE } from '@app/unraid-api/graph/resolvers/connect/connect.model.js';
interface UrlForFieldInput {
url: string;

View File

@@ -1,86 +0,0 @@
import type { RemoteGraphQlEventFragmentFragment } from '@app/graphql/generated/client/graphql.js';
import { remoteQueryLogger } from '@app/core/log.js';
import { getApiApolloClient } from '@app/graphql/client/api/get-api-client.js';
import { RemoteGraphQlEventType } from '@app/graphql/generated/client/graphql.js';
import { SEND_REMOTE_QUERY_RESPONSE } from '@app/graphql/mothership/mutations.js';
import { parseGraphQLQuery } from '@app/graphql/resolvers/subscription/remote-graphql/remote-graphql-helpers.js';
import { GraphQLClient } from '@app/mothership/graphql-client.js';
import { getters } from '@app/store/index.js';
export const executeRemoteGraphQLQuery = async (
data: RemoteGraphQlEventFragmentFragment['remoteGraphQLEventData']
) => {
remoteQueryLogger.debug({ query: data }, 'Executing remote query');
const client = GraphQLClient.getInstance();
const localApiKey = getters.config().remote.localApiKey;
if (!localApiKey) {
throw new Error('Local API key is missing');
}
const apiKey = localApiKey;
const originalBody = data.body;
try {
const parsedQuery = parseGraphQLQuery(originalBody);
const localClient = getApiApolloClient({
localApiKey: apiKey,
});
remoteQueryLogger.trace({ query: parsedQuery.query }, '[DEVONLY] Running query');
const localResult = await localClient.query({
query: parsedQuery.query,
variables: parsedQuery.variables,
});
if (localResult.data) {
remoteQueryLogger.trace(
{ data: localResult.data },
'Got data from remoteQuery request',
data.sha256
);
await client?.mutate({
mutation: SEND_REMOTE_QUERY_RESPONSE,
variables: {
input: {
sha256: data.sha256,
body: JSON.stringify({ data: localResult.data }),
type: RemoteGraphQlEventType.REMOTE_QUERY_EVENT,
},
},
errorPolicy: 'none',
});
} else {
// @TODO fix this not sending an error
await client?.mutate({
mutation: SEND_REMOTE_QUERY_RESPONSE,
variables: {
input: {
sha256: data.sha256,
body: JSON.stringify({ errors: localResult.error }),
type: RemoteGraphQlEventType.REMOTE_QUERY_EVENT,
},
},
});
}
} catch (err: unknown) {
try {
await client?.mutate({
mutation: SEND_REMOTE_QUERY_RESPONSE,
variables: {
input: {
sha256: data.sha256,
body: JSON.stringify({ errors: err }),
type: RemoteGraphQlEventType.REMOTE_QUERY_EVENT,
},
},
});
} catch (error) {
remoteQueryLogger.warn('Could not respond %o', error);
}
remoteQueryLogger.error(
'Error executing remote query %s',
err instanceof Error ? err.message : 'Unknown Error'
);
remoteQueryLogger.trace(err);
}
};

View File

@@ -1,9 +0,0 @@
import { type RemoteGraphQlEventFragmentFragment } from '@app/graphql/generated/client/graphql.js';
import { addRemoteSubscription } from '@app/store/actions/add-remote-subscription.js';
import { store } from '@app/store/index.js';
export const createRemoteSubscription = async (
data: RemoteGraphQlEventFragmentFragment['remoteGraphQLEventData']
) => {
await store.dispatch(addRemoteSubscription(data));
};

View File

@@ -83,7 +83,9 @@ export const getLocalServer = (getState = store.getState): Array<Server> => {
return [
{
id: 'local',
owner: {
id: 'local',
username: config.remote.username ?? 'root',
url: '',
avatar: '',

View File

@@ -15,9 +15,9 @@ import { WebSocket } from 'ws';
import { logger } from '@app/core/log.js';
import { fileExistsSync } from '@app/core/utils/files/file-exists.js';
import { getServerIdentifier } from '@app/core/utils/server-identifier.js';
import { environment, PATHS_CONFIG_MODULES, PORT } from '@app/environment.js';
import * as envVars from '@app/environment.js';
import { setupNewMothershipSubscription } from '@app/mothership/subscribe-to-mothership.js';
import { loadDynamixConfigFile } from '@app/store/actions/load-dynamix-config-file.js';
import { shutdownApiEvent } from '@app/store/actions/shutdown-api-event.js';
import { store } from '@app/store/index.js';
@@ -40,8 +40,25 @@ const unlinkUnixPort = () => {
export const viteNodeApp = async () => {
try {
await import('json-bigint-patch');
environment.IS_MAIN_PROCESS = true;
/**------------------------------------------------------------------------
* Attaching getServerIdentifier to globalThis
* getServerIdentifier is tightly coupled to the deprecated redux store,
* which we don't want to share with other packages or plugins.
*
* At the same time, we need to use it in @unraid/shared as a building block,
* where it's used & available outside of NestJS's DI context.
*
* Attaching to globalThis is a temporary solution to avoid refactoring
* config sync & management outside of NestJS's DI context.
*
* Plugin authors should import getServerIdentifier from @unraid/shared instead,
* to avoid breaking changes to their code.
*------------------------------------------------------------------------**/
globalThis.getServerIdentifier = getServerIdentifier;
logger.info('ENV %o', envVars);
logger.info('PATHS %o', store.getState().paths);
@@ -70,8 +87,6 @@ export const viteNodeApp = async () => {
// Load my dynamix config file into store
await store.dispatch(loadDynamixConfigFile());
await setupNewMothershipSubscription();
// Start listening to file updates
StateManager.getInstance();

View File

@@ -1,295 +0,0 @@
import type { NormalizedCacheObject } from '@apollo/client/core/index.js';
import type { Client, Event as ClientEvent } from 'graphql-ws';
import { ApolloClient, ApolloLink, InMemoryCache, Observable } from '@apollo/client/core/index.js';
import { ErrorLink } from '@apollo/client/link/error/index.js';
import { RetryLink } from '@apollo/client/link/retry/index.js';
import { GraphQLWsLink } from '@apollo/client/link/subscriptions/index.js';
import { createClient } from 'graphql-ws';
import { WebSocket } from 'ws';
import { FIVE_MINUTES_MS } from '@app/consts.js';
import { minigraphLogger } from '@app/core/log.js';
import { API_VERSION, MOTHERSHIP_GRAPHQL_LINK } from '@app/environment.js';
import { buildDelayFunction } from '@app/mothership/utils/delay-function.js';
import {
getMothershipConnectionParams,
getMothershipWebsocketHeaders,
} from '@app/mothership/utils/get-mothership-websocket-headers.js';
import { setGraphqlConnectionStatus } from '@app/store/actions/set-minigraph-status.js';
import { getters, store } from '@app/store/index.js';
import { logoutUser } from '@app/store/modules/config.js';
import { receivedMothershipPing, setMothershipTimeout } from '@app/store/modules/minigraph.js';
import { MinigraphStatus } from '@app/unraid-api/graph/resolvers/cloud/cloud.model.js';
const getWebsocketWithMothershipHeaders = () => {
return class WebsocketWithMothershipHeaders extends WebSocket {
constructor(address, protocols) {
super(address, protocols, {
headers: getMothershipWebsocketHeaders(),
});
}
};
};
const delayFn = buildDelayFunction({
jitter: true,
max: FIVE_MINUTES_MS,
initial: 10_000,
});
/**
* Checks that API_VERSION, config.remote.apiKey, emhttp.var.flashGuid, and emhttp.var.version are all set before returning true\
* Also checks that the API Key has passed Validation from Keyserver
* @returns boolean, are variables set
*/
export const isAPIStateDataFullyLoaded = (state = store.getState()) => {
const { config, emhttp } = state;
return (
Boolean(API_VERSION) &&
Boolean(config.remote.apikey) &&
Boolean(emhttp.var.flashGuid) &&
Boolean(emhttp.var.version)
);
};
const isInvalidApiKeyError = (error: unknown) =>
error instanceof Error && error.message.includes('API Key Invalid');
export class GraphQLClient {
public static instance: ApolloClient<NormalizedCacheObject> | null = null;
public static client: Client | null = null;
private constructor() {}
/**
* Get a singleton GraphQL instance (if possible given loaded state)
* @returns ApolloClient instance or null, if state is not valid
*/
public static getInstance(): ApolloClient<NormalizedCacheObject> | null {
const isStateValid = isAPIStateDataFullyLoaded();
if (!isStateValid) {
minigraphLogger.error('GraphQL Client is not valid. Returning null for instance');
return null;
}
return GraphQLClient.instance;
}
/**
* This function is used to create a new Apollo instance (if it is possible to do so)
* This is used in order to facilitate a single instance existing at a time
* @returns Apollo Instance (if creation was possible)
*/
public static createSingletonInstance = () => {
const isStateValid = isAPIStateDataFullyLoaded();
if (!GraphQLClient.instance && isStateValid) {
minigraphLogger.debug('Creating a new Apollo Client Instance');
GraphQLClient.instance = GraphQLClient.createGraphqlClient();
}
return GraphQLClient.instance;
};
public static clearInstance = async () => {
if (this.instance) {
await this.instance.clearStore();
this.instance?.stop();
}
if (GraphQLClient.client) {
GraphQLClient.clearClientEventHandlers();
GraphQLClient.client.terminate();
await GraphQLClient.client.dispose();
GraphQLClient.client = null;
}
GraphQLClient.instance = null;
GraphQLClient.client = null;
minigraphLogger.trace('Cleared GraphQl client & instance');
};
static createGraphqlClient() {
/** a graphql-ws client to communicate with mothership if user opts-in */
GraphQLClient.client = createClient({
url: MOTHERSHIP_GRAPHQL_LINK.replace('http', 'ws'),
webSocketImpl: getWebsocketWithMothershipHeaders(),
connectionParams: () => getMothershipConnectionParams(),
});
const wsLink = new GraphQLWsLink(GraphQLClient.client);
const { appErrorLink, retryLink, errorLink } = GraphQLClient.createApolloLinks();
const apolloClient = new ApolloClient({
link: ApolloLink.from([appErrorLink, retryLink, errorLink, wsLink]),
cache: new InMemoryCache(),
defaultOptions: {
watchQuery: {
fetchPolicy: 'no-cache',
errorPolicy: 'all',
},
query: {
fetchPolicy: 'no-cache',
errorPolicy: 'all',
},
},
});
GraphQLClient.initEventHandlers();
return apolloClient;
}
/**
* Creates and configures Apollo links for error handling and retries
*
* @returns Object containing configured Apollo links:
* - appErrorLink: Prevents errors from bubbling "up" & potentially crashing the API
* - retryLink: Handles retrying failed operations with exponential backoff
* - errorLink: Handles GraphQL and network errors, including API key validation and connection status updates
*/
static createApolloLinks() {
/** prevents errors from bubbling beyond this link/apollo instance & potentially crashing the api */
const appErrorLink = new ApolloLink((operation, forward) => {
return new Observable((observer) => {
forward(operation).subscribe({
next: (result) => observer.next(result),
error: (error) => {
minigraphLogger.warn('Apollo error, will not retry: %s', error?.message);
observer.complete();
},
complete: () => observer.complete(),
});
});
});
/**
* Max # of times to retry authenticating with mothership.
* Total # of attempts will be retries + 1.
*/
const MAX_AUTH_RETRIES = 3;
const retryLink = new RetryLink({
delay(count, operation, error) {
const getDelay = delayFn(count);
operation.setContext({ retryCount: count });
store.dispatch(setMothershipTimeout(getDelay));
minigraphLogger.info('Delay currently is: %i', getDelay);
return getDelay;
},
attempts: {
max: Infinity,
retryIf: (error, operation) => {
const { retryCount = 0 } = operation.getContext();
// i.e. retry api key errors up to 3 times (4 attempts total)
return !isInvalidApiKeyError(error) || retryCount < MAX_AUTH_RETRIES;
},
},
});
const errorLink = new ErrorLink((handler) => {
const { retryCount = 0 } = handler.operation.getContext();
minigraphLogger.debug(`Operation attempt: #${retryCount}`);
if (handler.graphQLErrors) {
// GQL Error Occurred, we should log and move on
minigraphLogger.info('GQL Error Encountered %o', handler.graphQLErrors);
} else if (handler.networkError) {
/**----------------------------------------------
* Handling of Network Errors
*
* When the handler has a void return,
* the network error will bubble up
* (i.e. left in the `ApolloLink.from` array).
*
* The underlying operation/request
* may be retried per the retry link.
*
* If the error is not retried, it will bubble
* into the appErrorLink and terminate there.
*---------------------------------------------**/
minigraphLogger.error(handler.networkError, 'Network Error');
const error = handler.networkError;
if (error?.message?.includes('to be an array of GraphQL errors, but got')) {
minigraphLogger.warn('detected malformed graphql error in websocket message');
}
if (isInvalidApiKeyError(error)) {
if (retryCount >= MAX_AUTH_RETRIES) {
store
.dispatch(logoutUser({ reason: 'Invalid API Key on Mothership' }))
.catch((err) => {
minigraphLogger.error(err, 'Error during logout');
});
}
} else if (getters.minigraph().status !== MinigraphStatus.ERROR_RETRYING) {
store.dispatch(
setGraphqlConnectionStatus({
status: MinigraphStatus.ERROR_RETRYING,
error: handler.networkError.message,
})
);
}
}
});
return { appErrorLink, retryLink, errorLink } as const;
}
/**
* Initialize event handlers for the GraphQL client websocket connection
*
* Sets up handlers for:
* - 'connecting': Updates store with connecting status and logs connection attempt
* - 'error': Logs any GraphQL client errors
* - 'connected': Updates store with connected status and logs successful connection
* - 'ping': Handles ping messages from mothership to track connection health
*
* @param client - The GraphQL client instance to attach handlers to. Defaults to GraphQLClient.client
* @returns void
*/
private static initEventHandlers(client = GraphQLClient.client): void {
if (!client) return;
// Maybe a listener to initiate this
client.on('connecting', () => {
store.dispatch(
setGraphqlConnectionStatus({
status: MinigraphStatus.CONNECTING,
error: null,
})
);
minigraphLogger.info('Connecting to %s', MOTHERSHIP_GRAPHQL_LINK.replace('http', 'ws'));
});
client.on('error', (err) => {
minigraphLogger.error('GraphQL Client Error: %o', err);
});
client.on('connected', () => {
store.dispatch(
setGraphqlConnectionStatus({
status: MinigraphStatus.CONNECTED,
error: null,
})
);
minigraphLogger.info('Connected to %s', MOTHERSHIP_GRAPHQL_LINK.replace('http', 'ws'));
});
client.on('ping', () => {
// Received ping from mothership
minigraphLogger.trace('ping');
store.dispatch(receivedMothershipPing());
});
}
/**
* Clears event handlers from the GraphQL client websocket connection
*
* Removes handlers for the specified events by replacing them with empty functions.
* This ensures no lingering event handlers remain when disposing of a client.
*
* @param client - The GraphQL client instance to clear handlers from. Defaults to GraphQLClient.client
* @param events - Array of event types to clear handlers for. Defaults to ['connected', 'connecting', 'error', 'ping']
* @returns void
*/
private static clearClientEventHandlers(
client = GraphQLClient.client,
events: ClientEvent[] = ['connected', 'connecting', 'error', 'ping']
): void {
if (!client) return;
events.forEach((eventName) => client.on(eventName, () => {}));
}
}

View File

@@ -1,125 +0,0 @@
import { CronJob } from 'cron';
import { KEEP_ALIVE_INTERVAL_MS, ONE_MINUTE_MS } from '@app/consts.js';
import { minigraphLogger, mothershipLogger, remoteAccessLogger } from '@app/core/log.js';
import { isAPIStateDataFullyLoaded } from '@app/mothership/graphql-client.js';
import { setGraphqlConnectionStatus } from '@app/store/actions/set-minigraph-status.js';
import { store } from '@app/store/index.js';
import { setRemoteAccessRunningType } from '@app/store/modules/dynamic-remote-access.js';
import { clearSubscription } from '@app/store/modules/remote-graphql.js';
import { MinigraphStatus } from '@app/unraid-api/graph/resolvers/cloud/cloud.model.js';
import { DynamicRemoteAccessType } from '@app/unraid-api/graph/resolvers/connect/connect.model.js';
class PingTimeoutJobs {
private cronJob: CronJob;
private isRunning: boolean = false;
constructor() {
// Run every minute
this.cronJob = new CronJob('* * * * *', this.checkForPingTimeouts.bind(this));
}
async checkForPingTimeouts() {
const state = store.getState();
if (!isAPIStateDataFullyLoaded(state)) {
mothershipLogger.warn('State data not fully loaded, but job has been started');
return;
}
// Check for ping timeouts in remote graphql events
const subscriptionsToClear = state.remoteGraphQL.subscriptions.filter(
(subscription) => Date.now() - subscription.lastPing > KEEP_ALIVE_INTERVAL_MS
);
if (subscriptionsToClear.length > 0) {
mothershipLogger.debug(
`Clearing %s / %s subscriptions that are older than ${
KEEP_ALIVE_INTERVAL_MS / 1_000 / 60
} minutes`,
subscriptionsToClear.length,
state.remoteGraphQL.subscriptions.length
);
}
subscriptionsToClear.forEach((sub) => store.dispatch(clearSubscription(sub.sha256)));
// Check for ping timeouts in mothership
if (
state.minigraph.lastPing &&
Date.now() - state.minigraph.lastPing > KEEP_ALIVE_INTERVAL_MS &&
state.minigraph.status === MinigraphStatus.CONNECTED
) {
minigraphLogger.error(
`NO PINGS RECEIVED IN ${
KEEP_ALIVE_INTERVAL_MS / 1_000 / 60
} MINUTES, SOCKET MUST BE RECONNECTED`
);
store.dispatch(
setGraphqlConnectionStatus({
status: MinigraphStatus.PING_FAILURE,
error: 'Ping Receive Exceeded Timeout',
})
);
}
// Check for ping timeouts from mothership events
if (
state.minigraph.selfDisconnectedSince &&
Date.now() - state.minigraph.selfDisconnectedSince > KEEP_ALIVE_INTERVAL_MS &&
state.minigraph.status === MinigraphStatus.CONNECTED
) {
minigraphLogger.error(`SELF DISCONNECTION EVENT NEVER CLEARED, SOCKET MUST BE RECONNECTED`);
store.dispatch(
setGraphqlConnectionStatus({
status: MinigraphStatus.PING_FAILURE,
error: 'Received disconnect event for own server',
})
);
}
// Check for ping timeouts in remote access
if (
state.dynamicRemoteAccess.lastPing &&
Date.now() - state.dynamicRemoteAccess.lastPing > ONE_MINUTE_MS
) {
remoteAccessLogger.error(`NO PINGS RECEIVED IN 1 MINUTE, REMOTE ACCESS MUST BE DISABLED`);
store.dispatch(setRemoteAccessRunningType(DynamicRemoteAccessType.DISABLED));
}
}
start() {
if (!this.isRunning) {
this.cronJob.start();
this.isRunning = true;
}
}
stop() {
if (this.isRunning) {
this.cronJob.stop();
this.isRunning = false;
}
}
isJobRunning(): boolean {
return this.isRunning;
}
}
let pingTimeoutJobs: PingTimeoutJobs | null = null;
export const initPingTimeoutJobs = (): boolean => {
if (!pingTimeoutJobs) {
pingTimeoutJobs = new PingTimeoutJobs();
}
pingTimeoutJobs.start();
return pingTimeoutJobs.isJobRunning();
};
export const stopPingTimeoutJobs = () => {
minigraphLogger.trace('Stopping Ping Timeout Jobs');
if (!pingTimeoutJobs) {
minigraphLogger.warn('PingTimeoutJobs Handler not found.');
return;
}
pingTimeoutJobs.stop();
pingTimeoutJobs = null;
};

View File

@@ -1,88 +0,0 @@
import { minigraphLogger, mothershipLogger } from '@app/core/log.js';
import { useFragment } from '@app/graphql/generated/client/fragment-masking.js';
import { ClientType } from '@app/graphql/generated/client/graphql.js';
import { EVENTS_SUBSCRIPTION, RemoteGraphQL_Fragment } from '@app/graphql/mothership/subscriptions.js';
import { GraphQLClient } from '@app/mothership/graphql-client.js';
import { initPingTimeoutJobs } from '@app/mothership/jobs/ping-timeout-jobs.js';
import { getMothershipConnectionParams } from '@app/mothership/utils/get-mothership-websocket-headers.js';
import { handleRemoteGraphQLEvent } from '@app/store/actions/handle-remote-graphql-event.js';
import { store } from '@app/store/index.js';
import { setSelfDisconnected, setSelfReconnected } from '@app/store/modules/minigraph.js';
import { notNull } from '@app/utils.js';
export const subscribeToEvents = async (apiKey: string) => {
minigraphLogger.info('Subscribing to Events');
const client = GraphQLClient.getInstance();
if (!client) {
throw new Error('Unable to use client - state must not be loaded');
}
const eventsSub = client.subscribe({
query: EVENTS_SUBSCRIPTION,
fetchPolicy: 'no-cache',
});
eventsSub.subscribe(async ({ data, errors }) => {
if (errors) {
mothershipLogger.error('GraphQL Error with events subscription: %s', errors.join(','));
} else if (data) {
mothershipLogger.trace({ events: data.events }, 'Got events from mothership');
for (const event of data.events?.filter(notNull) ?? []) {
switch (event.__typename) {
case 'ClientConnectedEvent': {
const {
connectedData: { type, apiKey: eventApiKey },
} = event;
// Another server connected to Mothership
if (type === ClientType.API) {
if (eventApiKey === apiKey) {
// We are online, clear timeout waiting if it's set
store.dispatch(setSelfReconnected());
}
}
break;
}
case 'ClientDisconnectedEvent': {
const {
disconnectedData: { type, apiKey: eventApiKey },
} = event;
// Server Disconnected From Mothership
if (type === ClientType.API) {
if (eventApiKey === apiKey) {
store.dispatch(setSelfDisconnected());
}
}
break;
}
case 'RemoteGraphQLEvent': {
const eventAsRemoteGraphQLEvent = useFragment(RemoteGraphQL_Fragment, event);
// No need to check API key here anymore
void store.dispatch(handleRemoteGraphQLEvent(eventAsRemoteGraphQLEvent));
break;
}
default:
break;
}
}
}
});
};
export const setupNewMothershipSubscription = async (state = store.getState()) => {
await GraphQLClient.clearInstance();
if (getMothershipConnectionParams(state)?.apiKey) {
minigraphLogger.trace('Creating Graphql client');
const client = GraphQLClient.createSingletonInstance();
if (client) {
minigraphLogger.trace('Connecting to mothership');
await subscribeToEvents(state.config.remote.apikey);
initPingTimeoutJobs();
}
}
};

View File

@@ -1,58 +0,0 @@
import { type OutgoingHttpHeaders } from 'node:http2';
import { logger } from '@app/core/log.js';
import { API_VERSION } from '@app/environment.js';
import { ClientType } from '@app/graphql/generated/client/graphql.js';
import { isAPIStateDataFullyLoaded } from '@app/mothership/graphql-client.js';
import { store } from '@app/store/index.js';
interface MothershipWebsocketHeaders extends OutgoingHttpHeaders {
'x-api-key': string;
'x-flash-guid': string;
'x-unraid-api-version': string;
'x-unraid-server-version': string;
'User-Agent': string;
}
export const getMothershipWebsocketHeaders = (
state = store.getState()
): MothershipWebsocketHeaders | OutgoingHttpHeaders => {
const { config, emhttp } = state;
if (isAPIStateDataFullyLoaded(state)) {
const headers: MothershipWebsocketHeaders = {
'x-api-key': config.remote.apikey,
'x-flash-guid': emhttp.var.flashGuid,
'x-unraid-api-version': API_VERSION,
'x-unraid-server-version': emhttp.var.version,
'User-Agent': `unraid-api/${API_VERSION}`,
};
logger.debug('Mothership websocket headers: %o', headers);
return headers;
}
return {};
};
interface MothershipConnectionParams extends Record<string, unknown> {
clientType: ClientType;
apiKey: string;
flashGuid: string;
apiVersion: string;
unraidVersion: string;
}
export const getMothershipConnectionParams = (
state = store.getState()
): MothershipConnectionParams | Record<string, unknown> => {
const { config, emhttp } = state;
if (isAPIStateDataFullyLoaded(state)) {
return {
clientType: ClientType.API,
apiKey: config.remote.apikey,
flashGuid: emhttp.var.flashGuid,
apiVersion: API_VERSION,
unraidVersion: emhttp.var.version,
};
}
return {};
};

View File

@@ -1,30 +0,0 @@
import { type AppDispatch, type RootState } from '@app/store/index.js';
import { AccessUrl } from '@app/unraid-api/graph/resolvers/connect/connect.model.js';
export interface GenericRemoteAccess {
beginRemoteAccess({
getState,
dispatch,
}: {
getState: () => RootState;
dispatch: AppDispatch;
}): Promise<AccessUrl | null>;
stopRemoteAccess({
getState,
dispatch,
}: {
getState: () => RootState;
dispatch: AppDispatch;
}): Promise<void>;
getRemoteAccessUrl({ getState }: { getState: () => RootState }): AccessUrl | null;
}
export interface IRemoteAccessController extends GenericRemoteAccess {
extendRemoteAccess({
getState,
dispatch,
}: {
getState: () => RootState;
dispatch: AppDispatch;
}): void;
}

View File

@@ -1,47 +0,0 @@
import { remoteAccessLogger } from '@app/core/log.js';
import { getServerIps } from '@app/graphql/resolvers/subscription/network.js';
import { type GenericRemoteAccess } from '@app/remoteAccess/handlers/remote-access-interface.js';
import { setWanAccessAndReloadNginx } from '@app/store/actions/set-wan-access-with-reload.js';
import { type AppDispatch, type RootState } from '@app/store/index.js';
import {
AccessUrl,
DynamicRemoteAccessType,
URL_TYPE,
} from '@app/unraid-api/graph/resolvers/connect/connect.model.js';
export class StaticRemoteAccess implements GenericRemoteAccess {
public getRemoteAccessUrl({ getState }: { getState: () => RootState }): AccessUrl | null {
const url = getServerIps(getState()).urls.find((url) => url.type === URL_TYPE.WAN);
return url ?? null;
}
async beginRemoteAccess({
getState,
dispatch,
}: {
getState: () => RootState;
dispatch: AppDispatch;
}): Promise<AccessUrl | null> {
const {
config: {
remote: { dynamicRemoteAccessType },
},
} = getState();
if (dynamicRemoteAccessType === DynamicRemoteAccessType.STATIC) {
remoteAccessLogger.debug('Enabling remote access for Static Client');
await dispatch(setWanAccessAndReloadNginx('yes'));
return this.getRemoteAccessUrl({ getState });
}
throw new Error('Invalid Parameters Passed to Static Remote Access Enabler');
}
async stopRemoteAccess({
dispatch,
}: {
getState: () => RootState;
dispatch: AppDispatch;
}): Promise<void> {
await dispatch(setWanAccessAndReloadNginx('no'));
}
}

View File

@@ -1,63 +0,0 @@
import { remoteAccessLogger } from '@app/core/log.js';
import { getServerIps } from '@app/graphql/resolvers/subscription/network.js';
import { type GenericRemoteAccess } from '@app/remoteAccess/handlers/remote-access-interface.js';
import { setWanAccessAndReloadNginx } from '@app/store/actions/set-wan-access-with-reload.js';
import { type AppDispatch, type RootState } from '@app/store/index.js';
import { disableUpnp, enableUpnp } from '@app/store/modules/upnp.js';
import {
AccessUrl,
DynamicRemoteAccessType,
URL_TYPE,
} from '@app/unraid-api/graph/resolvers/connect/connect.model.js';
export class UpnpRemoteAccess implements GenericRemoteAccess {
async stopRemoteAccess({ dispatch }: { getState: () => RootState; dispatch: AppDispatch }) {
// Stop
await dispatch(disableUpnp());
await dispatch(setWanAccessAndReloadNginx('no'));
}
public getRemoteAccessUrl({ getState }: { getState: () => RootState }): AccessUrl | null {
const urlsForServer = getServerIps(getState());
const url = urlsForServer.urls.find((url) => url.type === URL_TYPE.WAN) ?? null;
return url ?? null;
}
async beginRemoteAccess({
getState,
dispatch,
}: {
getState: () => RootState;
dispatch: AppDispatch;
}) {
// Stop Close Event
const state = getState();
const { dynamicRemoteAccessType } = state.config.remote;
if (dynamicRemoteAccessType === DynamicRemoteAccessType.UPNP && !state.upnp.upnpEnabled) {
const { portssl } = state.emhttp.var;
try {
const upnpEnableResult = await dispatch(enableUpnp({ portssl })).unwrap();
await dispatch(setWanAccessAndReloadNginx('yes'));
remoteAccessLogger.debug('UPNP Enable Result', upnpEnableResult);
if (!upnpEnableResult.wanPortForUpnp) {
throw new Error('Failed to get a WAN Port from UPNP');
}
return this.getRemoteAccessUrl({ getState });
} catch (error: unknown) {
remoteAccessLogger.warn('Caught error, disabling UPNP and re-throwing');
await this.stopRemoteAccess({ dispatch, getState });
throw new Error(
`UPNP Dynamic Remote Access Error: ${
error instanceof Error ? error.message : 'Unknown Error'
}`
);
}
}
throw new Error('Invalid Parameters Passed to UPNP Remote Access Enabler');
}
}

View File

@@ -1,139 +0,0 @@
import type { AppDispatch, RootState } from '@app/store/index.js';
import { remoteAccessLogger } from '@app/core/log.js';
import { UnraidLocalNotifier } from '@app/core/notifiers/unraid-local.js';
import { type IRemoteAccessController } from '@app/remoteAccess/handlers/remote-access-interface.js';
import { StaticRemoteAccess } from '@app/remoteAccess/handlers/static-remote-access.js';
import { UpnpRemoteAccess } from '@app/remoteAccess/handlers/upnp-remote-access.js';
import { getters } from '@app/store/index.js';
import {
clearPing,
receivedPing,
setDynamicRemoteAccessError,
setRemoteAccessRunningType,
} from '@app/store/modules/dynamic-remote-access.js';
import {
AccessUrl,
DynamicRemoteAccessType,
} from '@app/unraid-api/graph/resolvers/connect/connect.model.js';
export class RemoteAccessController implements IRemoteAccessController {
static _instance: RemoteAccessController | null = null;
activeRemoteAccess: UpnpRemoteAccess | StaticRemoteAccess | null = null;
notifier: UnraidLocalNotifier = new UnraidLocalNotifier({ level: 'info' });
constructor() {}
public static get instance(): RemoteAccessController {
if (!RemoteAccessController._instance) {
RemoteAccessController._instance = new RemoteAccessController();
}
return RemoteAccessController._instance;
}
getRunningRemoteAccessType() {
return getters.dynamicRemoteAccess().runningType;
}
public getRemoteAccessUrl({ getState }: { getState: () => RootState }): AccessUrl | null {
if (!this.activeRemoteAccess) {
return null;
}
return this.activeRemoteAccess.getRemoteAccessUrl({ getState });
}
async beginRemoteAccess({
getState,
dispatch,
}: {
getState: () => RootState;
dispatch: AppDispatch;
}) {
const state = getState();
const {
config: {
remote: { dynamicRemoteAccessType },
},
dynamicRemoteAccess: { runningType },
} = state;
if (!dynamicRemoteAccessType) {
// Should never get here
return null;
}
remoteAccessLogger.debug('Beginning remote access', runningType, dynamicRemoteAccessType);
if (runningType !== dynamicRemoteAccessType) {
await this.activeRemoteAccess?.stopRemoteAccess({
getState,
dispatch,
});
}
switch (dynamicRemoteAccessType) {
case DynamicRemoteAccessType.DISABLED:
this.activeRemoteAccess = null;
remoteAccessLogger.debug('Received begin event, but DRA is disabled.');
break;
case DynamicRemoteAccessType.UPNP:
remoteAccessLogger.debug('UPNP DRA Begin');
this.activeRemoteAccess = new UpnpRemoteAccess();
break;
case DynamicRemoteAccessType.STATIC:
remoteAccessLogger.debug('Static DRA Begin');
this.activeRemoteAccess = new StaticRemoteAccess();
break;
default:
break;
}
// Essentially a super call to the active type
try {
await this.activeRemoteAccess?.beginRemoteAccess({
getState,
dispatch,
});
dispatch(setRemoteAccessRunningType(dynamicRemoteAccessType));
this.extendRemoteAccess({ getState, dispatch });
await this.notifier.send({
title: 'Remote Access Started',
data: { message: 'Remote access has been started' },
});
} catch (error: unknown) {
dispatch(
setDynamicRemoteAccessError(error instanceof Error ? error.message : 'Unknown Error')
);
}
return null;
}
public extendRemoteAccess({
getState,
dispatch,
}: {
getState: () => RootState;
dispatch: AppDispatch;
}) {
dispatch(receivedPing());
return this.getRemoteAccessUrl({ getState });
}
async stopRemoteAccess({
getState,
dispatch,
}: {
getState: () => RootState;
dispatch: AppDispatch;
}) {
remoteAccessLogger.debug('Stopping remote access');
dispatch(clearPing());
await this.activeRemoteAccess?.stopRemoteAccess({ getState, dispatch });
dispatch(setRemoteAccessRunningType(DynamicRemoteAccessType.DISABLED));
await this.notifier.send({
title: 'Remote Access Stopped',
data: { message: 'Remote access has been stopped' },
});
}
}

View File

@@ -1,81 +0,0 @@
import { createAsyncThunk } from '@reduxjs/toolkit';
import type { RemoteGraphQlEventFragmentFragment } from '@app/graphql/generated/client/graphql.js';
import { remoteQueryLogger } from '@app/core/log.js';
import { getApiApolloClient } from '@app/graphql/client/api/get-api-client.js';
import { RemoteGraphQlEventType } from '@app/graphql/generated/client/graphql.js';
import { SEND_REMOTE_QUERY_RESPONSE } from '@app/graphql/mothership/mutations.js';
import { parseGraphQLQuery } from '@app/graphql/resolvers/subscription/remote-graphql/remote-graphql-helpers.js';
import { GraphQLClient } from '@app/mothership/graphql-client.js';
import { hasRemoteSubscription } from '@app/store/getters/index.js';
import { type AppDispatch, type RootState } from '@app/store/index.js';
import { type SubscriptionWithSha256 } from '@app/store/types.js';
export const addRemoteSubscription = createAsyncThunk<
SubscriptionWithSha256,
RemoteGraphQlEventFragmentFragment['remoteGraphQLEventData'],
{ state: RootState; dispatch: AppDispatch }
>('remoteGraphQL/addRemoteSubscription', async (data, { getState }) => {
if (hasRemoteSubscription(data.sha256, getState())) {
throw new Error(`Subscription Already Exists for SHA256: ${data.sha256}`);
}
const { config } = getState();
remoteQueryLogger.debug('Creating subscription for %o', data);
const apiKey = config.remote.localApiKey;
if (!apiKey) {
throw new Error('Local API key is missing');
}
const body = parseGraphQLQuery(data.body);
const client = getApiApolloClient({
localApiKey: apiKey,
});
const mothershipClient = GraphQLClient.getInstance();
const observable = client.subscribe({
query: body.query,
variables: body.variables,
});
const subscription = observable.subscribe({
async next(val) {
remoteQueryLogger.debug('Got value %o', val);
if (val.data) {
const result = await mothershipClient?.mutate({
mutation: SEND_REMOTE_QUERY_RESPONSE,
variables: {
input: {
sha256: data.sha256,
body: JSON.stringify({ data: val.data }),
type: RemoteGraphQlEventType.REMOTE_SUBSCRIPTION_EVENT,
},
},
});
remoteQueryLogger.debug('Remote Query Publish Result %o', result);
}
},
async error(errorValue) {
try {
await mothershipClient?.mutate({
mutation: SEND_REMOTE_QUERY_RESPONSE,
variables: {
input: {
sha256: data.sha256,
body: JSON.stringify({ errors: errorValue }),
type: RemoteGraphQlEventType.REMOTE_SUBSCRIPTION_EVENT,
},
},
});
} catch (error) {
remoteQueryLogger.info('Failed to mutate error result to endpoint');
}
remoteQueryLogger.error('Error executing remote subscription: %o', errorValue);
},
});
return {
sha256: data.sha256,
subscription,
};
});

View File

@@ -1,30 +0,0 @@
import { createAsyncThunk } from '@reduxjs/toolkit';
import type { RemoteGraphQlEventFragmentFragment } from '@app/graphql/generated/client/graphql.js';
import { remoteQueryLogger } from '@app/core/log.js';
import { RemoteGraphQlEventType } from '@app/graphql/generated/client/graphql.js';
import { executeRemoteGraphQLQuery } from '@app/graphql/resolvers/subscription/remote-graphql/remote-query.js';
import { createRemoteSubscription } from '@app/graphql/resolvers/subscription/remote-graphql/remote-subscription.js';
import { type AppDispatch, type RootState } from '@app/store/index.js';
import { renewRemoteSubscription } from '@app/store/modules/remote-graphql.js';
export const handleRemoteGraphQLEvent = createAsyncThunk<
void,
RemoteGraphQlEventFragmentFragment,
{ state: RootState; dispatch: AppDispatch }
>('dynamicRemoteAccess/handleRemoteAccessEvent', async (event, { dispatch }) => {
const data = event.remoteGraphQLEventData;
switch (data.type) {
case RemoteGraphQlEventType.REMOTE_MUTATION_EVENT:
break;
case RemoteGraphQlEventType.REMOTE_QUERY_EVENT:
remoteQueryLogger.debug('Responding to remote query event');
return await executeRemoteGraphQLQuery(event.remoteGraphQLEventData);
case RemoteGraphQlEventType.REMOTE_SUBSCRIPTION_EVENT:
remoteQueryLogger.debug('Responding to remote subscription event');
return await createRemoteSubscription(data);
case RemoteGraphQlEventType.REMOTE_SUBSCRIPTION_EVENT_PING:
await dispatch(renewRemoteSubscription({ sha256: data.sha256 }));
break;
}
});

View File

@@ -1,50 +0,0 @@
import { createAsyncThunk } from '@reduxjs/toolkit';
import { type AppDispatch, type RootState } from '@app/store/index.js';
import { type MyServersConfig } from '@app/types/my-servers-config.js';
import {
DynamicRemoteAccessType,
SetupRemoteAccessInput,
WAN_ACCESS_TYPE,
WAN_FORWARD_TYPE,
} from '@app/unraid-api/graph/resolvers/connect/connect.model.js';
const getDynamicRemoteAccessType = (
accessType: WAN_ACCESS_TYPE,
forwardType?: WAN_FORWARD_TYPE | undefined | null
): DynamicRemoteAccessType => {
// If access is disabled or always, DRA is disabled
if (accessType === WAN_ACCESS_TYPE.DISABLED || accessType === WAN_ACCESS_TYPE.ALWAYS) {
return DynamicRemoteAccessType.DISABLED;
}
// if access is enabled and forward type is UPNP, DRA is UPNP, otherwise it is static
return forwardType === WAN_FORWARD_TYPE.UPNP
? DynamicRemoteAccessType.UPNP
: DynamicRemoteAccessType.STATIC;
};
export const setupRemoteAccessThunk = createAsyncThunk<
Pick<MyServersConfig['remote'], 'wanaccess' | 'wanport' | 'dynamicRemoteAccessType' | 'upnpEnabled'>,
SetupRemoteAccessInput,
{ state: RootState; dispatch: AppDispatch }
>('config/setupRemoteAccess', async (payload) => {
if (payload.accessType === WAN_ACCESS_TYPE.DISABLED) {
return {
wanaccess: 'no',
wanport: '',
dynamicRemoteAccessType: DynamicRemoteAccessType.DISABLED,
upnpEnabled: 'no',
};
}
if (payload.forwardType === WAN_FORWARD_TYPE.STATIC && !payload.port) {
throw new Error('Missing port for WAN forward type STATIC');
}
return {
wanaccess: payload.accessType === WAN_ACCESS_TYPE.ALWAYS ? 'yes' : 'no',
wanport: payload.forwardType === WAN_FORWARD_TYPE.STATIC ? String(payload.port) : '',
dynamicRemoteAccessType: getDynamicRemoteAccessType(payload.accessType, payload.forwardType),
upnpEnabled: payload.forwardType === WAN_FORWARD_TYPE.UPNP ? 'yes' : 'no',
};
});

View File

@@ -1,20 +1,10 @@
import { logDestination, logger } from '@app/core/log.js';
import { setGraphqlConnectionStatus } from '@app/store/actions/set-minigraph-status.js';
import { store } from '@app/store/index.js';
import { stopListeners } from '@app/store/listeners/stop-listeners.js';
import { setWanAccess } from '@app/store/modules/config.js';
import { writeConfigSync } from '@app/store/sync/config-disk-sync.js';
import { MinigraphStatus } from '@app/unraid-api/graph/resolvers/cloud/cloud.model.js';
import { DynamicRemoteAccessType } from '@app/unraid-api/graph/resolvers/connect/connect.model.js';
export const shutdownApiEvent = () => {
logger.debug('Running shutdown');
stopListeners();
store.dispatch(setGraphqlConnectionStatus({ status: MinigraphStatus.PRE_INIT, error: null }));
if (store.getState().config.remote.dynamicRemoteAccessType !== DynamicRemoteAccessType.DISABLED) {
store.dispatch(setWanAccess('no'));
}
logger.debug('Writing final configs');
writeConfigSync('flash');
writeConfigSync('memory');

View File

@@ -1,18 +0,0 @@
import type { DNSCheck } from '@app/store/types.js';
import { getters, store } from '@app/store/index.js';
import { CacheKeys } from '@app/store/types.js';
import { type CloudResponse } from '@app/unraid-api/graph/resolvers/cloud/cloud.model.js';
export const getCloudCache = (): CloudResponse | undefined => {
const { nodeCache } = getters.cache();
return nodeCache.get(CacheKeys.checkCloud);
};
export const getDnsCache = (): DNSCheck | undefined => {
const { nodeCache } = getters.cache();
return nodeCache.get(CacheKeys.checkDns);
};
export const hasRemoteSubscription = (sha256: string, state = store.getState()): boolean => {
return state.remoteGraphQL.subscriptions.some((sub) => sub.sha256 === sha256);
};

View File

@@ -8,7 +8,7 @@ export const store = configureStore({
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false,
}).prepend(listenerMiddleware.middleware),
}).prepend(listenerMiddleware?.middleware ?? []),
});
export type RootState = ReturnType<typeof store.getState>;
@@ -16,14 +16,11 @@ export type AppDispatch = typeof store.dispatch;
export type ApiStore = typeof store;
export const getters = {
cache: () => store.getState().cache,
config: () => store.getState().config,
dynamicRemoteAccess: () => store.getState().dynamicRemoteAccess,
dynamix: () => store.getState().dynamix,
emhttp: () => store.getState().emhttp,
minigraph: () => store.getState().minigraph,
paths: () => store.getState().paths,
registration: () => store.getState().registration,
remoteGraphQL: () => store.getState().remoteGraphQL,
upnp: () => store.getState().upnp,
};

View File

@@ -1,56 +0,0 @@
import { isAnyOf } from '@reduxjs/toolkit';
import { remoteAccessLogger } from '@app/core/log.js';
import { RemoteAccessController } from '@app/remoteAccess/remote-access-controller.js';
import { type RootState } from '@app/store/index.js';
import { startAppListening } from '@app/store/listeners/listener-middleware.js';
import { loadConfigFile } from '@app/store/modules/config.js';
import { FileLoadStatus } from '@app/store/types.js';
import { DynamicRemoteAccessType } from '@app/unraid-api/graph/resolvers/connect/connect.model.js';
const shouldDynamicRemoteAccessBeEnabled = (state: RootState | null): boolean => {
if (
state?.config.status !== FileLoadStatus.LOADED ||
state?.emhttp.status !== FileLoadStatus.LOADED
) {
return false;
}
if (
state.config.remote.dynamicRemoteAccessType &&
state.config.remote.dynamicRemoteAccessType !== DynamicRemoteAccessType.DISABLED
) {
return true;
}
return false;
};
const isStateOrConfigUpdate = isAnyOf(loadConfigFile.fulfilled);
export const enableDynamicRemoteAccessListener = () =>
startAppListening({
predicate(action, currentState, previousState) {
if (
(isStateOrConfigUpdate(action) || !action?.type) &&
shouldDynamicRemoteAccessBeEnabled(currentState) !==
shouldDynamicRemoteAccessBeEnabled(previousState)
) {
return true;
}
return false;
},
async effect(_, { getState, dispatch }) {
const state = getState();
const remoteAccessType = state.config.remote?.dynamicRemoteAccessType;
if (!remoteAccessType) {
return;
}
if (remoteAccessType === DynamicRemoteAccessType.DISABLED) {
remoteAccessLogger.info('[Listener] Disabling Dynamic Remote Access Feature');
await RemoteAccessController.instance.stopRemoteAccess({ getState, dispatch });
}
},
});

View File

@@ -6,12 +6,8 @@ import { addListener, createListenerMiddleware } from '@reduxjs/toolkit';
import { type AppDispatch, type RootState } from '@app/store/index.js';
import { enableArrayEventListener } from '@app/store/listeners/array-event-listener.js';
import { enableConfigFileListener } from '@app/store/listeners/config-listener.js';
import { enableDynamicRemoteAccessListener } from '@app/store/listeners/dynamic-remote-access-listener.js';
import { enableMothershipJobsListener } from '@app/store/listeners/mothership-subscription-listener.js';
import { enableServerStateListener } from '@app/store/listeners/server-state-listener.js';
import { enableUpnpListener } from '@app/store/listeners/upnp-listener.js';
import { enableVersionListener } from '@app/store/listeners/version-listener.js';
import { enableWanAccessChangeListener } from '@app/store/listeners/wan-access-change-listener.js';
export const listenerMiddleware = createListenerMiddleware();
@@ -25,13 +21,9 @@ export const addAppListener = addListener as TypedAddListener<RootState, AppDisp
export const startMiddlewareListeners = () => {
// Begin listening for events
enableMothershipJobsListener();
enableConfigFileListener('flash')();
enableConfigFileListener('memory')();
enableUpnpListener();
enableVersionListener();
enableDynamicRemoteAccessListener();
enableArrayEventListener();
enableWanAccessChangeListener();
enableServerStateListener();
};

View File

@@ -1,41 +0,0 @@
import { isEqual } from 'lodash-es';
import { minigraphLogger } from '@app/core/log.js';
import { setupNewMothershipSubscription } from '@app/mothership/subscribe-to-mothership.js';
import { getMothershipConnectionParams } from '@app/mothership/utils/get-mothership-websocket-headers.js';
import { setGraphqlConnectionStatus } from '@app/store/actions/set-minigraph-status.js';
import { startAppListening } from '@app/store/listeners/listener-middleware.js';
import { MinigraphStatus } from '@app/unraid-api/graph/resolvers/cloud/cloud.model.js';
export const enableMothershipJobsListener = () =>
startAppListening({
predicate(action, currentState, previousState) {
const newConnectionParams = !isEqual(
getMothershipConnectionParams(currentState),
getMothershipConnectionParams(previousState)
);
const apiKey = getMothershipConnectionParams(currentState)?.apiKey;
// This event happens on first app load, or if a user signs out and signs back in, etc
if (newConnectionParams && apiKey) {
minigraphLogger.info('Connecting / Reconnecting Mothership Due to Changed Config File');
return true;
}
if (
setGraphqlConnectionStatus.match(action) &&
[MinigraphStatus.PING_FAILURE, MinigraphStatus.PRE_INIT].includes(action.payload.status)
) {
minigraphLogger.info(
'Reconnecting Mothership - PING_FAILURE / PRE_INIT - SetGraphQLConnectionStatus Event'
);
return true;
}
return false;
},
async effect(_, { getState }) {
minigraphLogger.trace('Renewing mothership subscription');
await setupNewMothershipSubscription(getState());
},
});

Some files were not shown because too many files have changed in this diff Show More