diff --git a/.gitignore b/.gitignore index bc5394b..47d18d6 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,5 @@ src/storybook-static/ *.tsbuildinfo .DS_Store npm-debug.log* -utils/Release-Package/.npmrc.release-temp +utils/src/engines/release/.npmrc.release-temp src/.npmrc.release-temp diff --git a/CHANGELOG.md b/CHANGELOG.md index dfe6f24..4b85612 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,24 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.3.3] - 2026-05-31 + +### Changed + +- Migrated `utils/` to maksit-repoutils **1.0.14** layout under `utils/src/` (`Invoke-ReleasePackage`, `Invoke-TestEngine`, `Update-RepoUtils`). Product `scriptSettings.json` paths updated for the deeper engine folders. + +### Added + +- `@maks-it.com/webui-core`: `useWebUiHub` React hook for JWT-authenticated SignalR hubs — connection state (`idle` / `connecting` / `connected` / `reconnecting` / `disconnected`), optional automatic reconnect, and typed hub event handlers. +- `resolveHubUrl` helper (absolute URLs unchanged; relative paths resolve against `window.location.origin`). +- `@microsoft/signalr` peer dependency on `@maks-it.com/webui-core`. + +### Changed + +- All `@maks-it.com/webui-*` packages published at `0.3.3` with aligned workspace dependency ranges. +- Jest tests for core and contracts moved from co-located `src/**/*.test.ts` to `packages/*/test/`; root `jest.config.cjs` roots updated accordingly. +- `@maks-it.com/webui-core` README documents SignalR install and `useWebUiHub` usage. + ## [0.3.2] - 2026-05-30 ### Fixed diff --git a/README.md b/README.md index e52920c..1fc114a 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Shared React UI library for **maksit-certs-ui** and **maksit-vault** WebUI apps. | `@maks-it.com/webui-core` | Utilities (`deepDelta`, enum helpers, ACL parsers) and `useFormState` | | `@maks-it.com/webui-components` | React components, layout, editors, DataTable, auth shell | -Source lives under `src/` (npm workspaces). Release automation lives under `utils/` (from [maksit-repoutils](https://github.com/MAKS-IT-COM/maksit-repoutils)). +Source lives under `src/` (npm workspaces). Release automation lives under `utils/src/` (from [maksit-repoutils](https://github.com/MAKS-IT-COM/maksit-repoutils)). ## Local development @@ -26,15 +26,15 @@ npm run storybook **Storybook** (`npm run storybook`) runs a local catalog of `@maks-it.com/webui-components` with Tailwind, React Router, autodocs, a11y checks, and **Vitest component tests** (testing widget + `npm run test-storybook`). Stories live under `src/stories/components/` (mirroring component folders); see `src/stories/README.md` for story conventions and testing. -Tests and coverage badges: **`utils/Run-Tests/Run-Tests.bat`** (plugin config in `utils/Run-Tests/scriptsettings.json`; uses `NpmJestTest`). +Tests and coverage badges: **`utils/src/Invoke-TestEngine.bat`** (plugin config in `utils/src/engines/test/scriptSettings.json`; uses `NpmJestTest`). ## Release to npmjs 1. Set **`NPMJS_MAKS_IT`** to your npm automation token (same pattern as `NUGET_MAKS_IT` for NuGet). 2. Bump **`src/package.json`** `version` (and tag `vX.Y.Z` on `main` when using the publish guard). -3. Run **`utils/Release-Package/Release-Package.bat`** (or `pwsh utils/Release-Package/Release-Package.ps1`). +3. Run **`utils/src/Invoke-ReleasePackage.bat`** (or `pwsh utils/src/engines/release/Invoke-ReleasePackage.ps1`). -Configured plugins (see `utils/Release-Package/scriptsettings.json`): +Configured plugins (see `utils/src/engines/release/scriptSettings.json`): | Plugin | Role | |--------|------| @@ -44,7 +44,7 @@ Configured plugins (see `utils/Release-Package/scriptsettings.json`): | `GitHub` | GitHub release (optional; needs `GITHUB_MAKS_IT_COM`) | | `NpmPublish` | Publish workspace packages in dependency order | -Refresh shared utils from repoutils: **`utils/Update-RepoUtils/Update-RepoUtils.bat`**. +Refresh shared utils from repoutils: **`utils/src/Update-RepoUtils.bat`**. ## Consume in product repos diff --git a/assets/badges/coverage-branches.svg b/assets/badges/coverage-branches.svg index 74be9ef..0d2ffe0 100644 --- a/assets/badges/coverage-branches.svg +++ b/assets/badges/coverage-branches.svg @@ -1,5 +1,5 @@ - - Branch Coverage: 48% + + Branch Coverage: 72% @@ -9,13 +9,13 @@ - + Branch Coverage - - 48% + + 72% diff --git a/assets/badges/coverage-lines.svg b/assets/badges/coverage-lines.svg index dba109a..b8bfce8 100644 --- a/assets/badges/coverage-lines.svg +++ b/assets/badges/coverage-lines.svg @@ -1,21 +1,21 @@ - - Line Coverage: 42% + + Line Coverage: 75.2% - + - - + + Line Coverage - - 42% + + 75.2% diff --git a/assets/badges/coverage-methods.svg b/assets/badges/coverage-methods.svg index 7789289..8a48dd4 100644 --- a/assets/badges/coverage-methods.svg +++ b/assets/badges/coverage-methods.svg @@ -1,5 +1,5 @@ - - Method Coverage: 20.3% + + Method Coverage: 66.7% @@ -9,13 +9,13 @@ - + Method Coverage - - 20.3% + + 66.7% diff --git a/assets/docs/NPM_PUBLISH.md b/assets/docs/NPM_PUBLISH.md index 18f872e..a0ae1fa 100644 --- a/assets/docs/NPM_PUBLISH.md +++ b/assets/docs/NPM_PUBLISH.md @@ -50,13 +50,13 @@ npm view @maks-it.com/webui-components version ## Release pipeline (recommended) -Use **`utils/Release-Package/Release-Package.bat`** (or `pwsh utils/Release-Package/Release-Package.ps1`): +Use **`utils/src/Invoke-ReleasePackage.bat`** (or `pwsh utils/src/engines/release/Invoke-ReleasePackage.ps1`): 1. Bump version in `src/package.json` (or tag drives `NpmReleaseVersion`). 2. Tag `HEAD` with exact semver, e.g. `git tag v0.2.0 && git push origin v0.2.0`. 3. Set `NPMJS_MAKS_IT` and run the release engine. -`utils/Release-Package/scriptsettings.json` runs `NpmReleaseVersion`, `NpmBuild`, `ReleasePublishGuard`, optional `GitHub`, then `NpmPublish` in dependency order. +`utils/src/engines/release/scriptSettings.json` runs `NpmReleaseVersion`, `NpmBuild`, `ReleasePublishGuard`, optional `GitHub`, then `NpmPublish` in dependency order. ## After publish — Certs UI / Vault diff --git a/src/coverage/coverage-summary.json b/src/coverage/coverage-summary.json index 604cb58..1ef1a18 100644 --- a/src/coverage/coverage-summary.json +++ b/src/coverage/coverage-summary.json @@ -1,4 +1,4 @@ -{"total": {"lines":{"total":837,"covered":352,"skipped":0,"pct":42.05},"statements":{"total":902,"covered":377,"skipped":0,"pct":41.79},"functions":{"total":212,"covered":43,"skipped":0,"pct":20.28},"branches":{"total":404,"covered":194,"skipped":0,"pct":48.01},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":100}} +{"total": {"lines":{"total":481,"covered":362,"skipped":0,"pct":75.25},"statements":{"total":514,"covered":389,"skipped":0,"pct":75.68},"functions":{"total":66,"covered":44,"skipped":0,"pct":66.66},"branches":{"total":279,"covered":201,"skipped":0,"pct":72.04},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\contracts\\src\\PagedRequest.ts": {"lines":{"total":3,"covered":3,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":3,"covered":3,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\contracts\\src\\PatchOperation.ts": {"lines":{"total":6,"covered":6,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":6,"covered":6,"skipped":0,"pct":100},"branches":{"total":2,"covered":2,"skipped":0,"pct":100}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\contracts\\src\\PatchRequestModelBase.ts": {"lines":{"total":4,"covered":4,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":4,"covered":4,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} @@ -8,54 +8,22 @@ ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\contracts\\src\\identity\\login\\LoginRequest.ts": {"lines":{"total":9,"covered":9,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":9,"covered":9,"skipped":0,"pct":100},"branches":{"total":8,"covered":8,"skipped":0,"pct":100}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\contracts\\src\\identity\\login\\RefreshTokenRequest.ts": {"lines":{"total":2,"covered":2,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":2,"covered":2,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\contracts\\src\\identity\\logout\\LogoutRequest.ts": {"lines":{"total":2,"covered":2,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":2,"covered":2,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\index.ts": {"lines":{"total":5,"covered":0,"skipped":0,"pct":0},"functions":{"total":4,"covered":0,"skipped":0,"pct":0},"statements":{"total":9,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\index.ts": {"lines":{"total":47,"covered":0,"skipped":0,"pct":0},"functions":{"total":38,"covered":0,"skipped":0,"pct":0},"statements":{"total":47,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\acl\\index.ts": {"lines":{"total":1,"covered":0,"skipped":0,"pct":0},"functions":{"total":2,"covered":0,"skipped":0,"pct":0},"statements":{"total":3,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\acl\\parseAclEntry.ts": {"lines":{"total":17,"covered":17,"skipped":0,"pct":100},"functions":{"total":4,"covered":4,"skipped":0,"pct":100},"statements":{"total":18,"covered":18,"skipped":0,"pct":100},"branches":{"total":6,"covered":6,"skipped":0,"pct":100}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\dataTable\\dataTableFilters.ts": {"lines":{"total":5,"covered":5,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":6,"covered":6,"skipped":0,"pct":100},"branches":{"total":2,"covered":2,"skipped":0,"pct":100}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\dataTable\\dataTablePaged.ts": {"lines":{"total":4,"covered":4,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":4,"covered":4,"skipped":0,"pct":100},"branches":{"total":16,"covered":16,"skipped":0,"pct":100}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\dataTable\\index.ts": {"lines":{"total":4,"covered":0,"skipped":0,"pct":0},"functions":{"total":2,"covered":0,"skipped":0,"pct":0},"statements":{"total":4,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\date\\dateTimeToUtcIsoSchema.ts": {"lines":{"total":8,"covered":0,"skipped":0,"pct":0},"functions":{"total":2,"covered":0,"skipped":0,"pct":0},"statements":{"total":8,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\date\\formatISODateString.ts": {"lines":{"total":10,"covered":0,"skipped":0,"pct":0},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":10,"covered":0,"skipped":0,"pct":0},"branches":{"total":4,"covered":0,"skipped":0,"pct":0}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\date\\index.ts": {"lines":{"total":12,"covered":0,"skipped":0,"pct":0},"functions":{"total":9,"covered":0,"skipped":0,"pct":0},"statements":{"total":13,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\date\\isValidDateString.ts": {"lines":{"total":6,"covered":6,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":7,"covered":7,"skipped":0,"pct":100},"branches":{"total":2,"covered":2,"skipped":0,"pct":100}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\deep\\deepCopy.ts": {"lines":{"total":17,"covered":16,"skipped":0,"pct":94.11},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":17,"covered":16,"skipped":0,"pct":94.11},"branches":{"total":12,"covered":11,"skipped":0,"pct":91.66}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\deep\\deepDelta.ts": {"lines":{"total":183,"covered":119,"skipped":0,"pct":65.02},"functions":{"total":18,"covered":14,"skipped":0,"pct":77.77},"statements":{"total":199,"covered":130,"skipped":0,"pct":65.32},"branches":{"total":137,"covered":92,"skipped":0,"pct":67.15}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\deep\\deepEqual.ts": {"lines":{"total":36,"covered":35,"skipped":0,"pct":97.22},"functions":{"total":3,"covered":3,"skipped":0,"pct":100},"statements":{"total":38,"covered":37,"skipped":0,"pct":97.36},"branches":{"total":26,"covered":25,"skipped":0,"pct":96.15}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\deep\\deepMerge.ts": {"lines":{"total":21,"covered":0,"skipped":0,"pct":0},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":24,"covered":0,"skipped":0,"pct":0},"branches":{"total":17,"covered":0,"skipped":0,"pct":0}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\deep\\deepPatternMatch.ts": {"lines":{"total":10,"covered":0,"skipped":0,"pct":0},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":14,"covered":0,"skipped":0,"pct":0},"branches":{"total":10,"covered":0,"skipped":0,"pct":0}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\deep\\index.ts": {"lines":{"total":15,"covered":0,"skipped":0,"pct":0},"functions":{"total":9,"covered":0,"skipped":0,"pct":0},"statements":{"total":15,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\deep\\patchCollectionPolicies.ts": {"lines":{"total":16,"covered":0,"skipped":0,"pct":0},"functions":{"total":5,"covered":0,"skipped":0,"pct":0},"statements":{"total":16,"covered":0,"skipped":0,"pct":0},"branches":{"total":16,"covered":0,"skipped":0,"pct":0}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\enum\\enumToArr.ts": {"lines":{"total":16,"covered":0,"skipped":0,"pct":0},"functions":{"total":3,"covered":0,"skipped":0,"pct":0},"statements":{"total":19,"covered":0,"skipped":0,"pct":0},"branches":{"total":10,"covered":0,"skipped":0,"pct":0}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\enum\\enumToObj.ts": {"lines":{"total":9,"covered":0,"skipped":0,"pct":0},"functions":{"total":2,"covered":0,"skipped":0,"pct":0},"statements":{"total":11,"covered":0,"skipped":0,"pct":0},"branches":{"total":4,"covered":0,"skipped":0,"pct":0}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\enum\\enumToString.ts": {"lines":{"total":11,"covered":0,"skipped":0,"pct":0},"functions":{"total":3,"covered":0,"skipped":0,"pct":0},"statements":{"total":12,"covered":0,"skipped":0,"pct":0},"branches":{"total":6,"covered":0,"skipped":0,"pct":0}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\enum\\flagsToString.ts": {"lines":{"total":6,"covered":0,"skipped":0,"pct":0},"functions":{"total":3,"covered":0,"skipped":0,"pct":0},"statements":{"total":6,"covered":0,"skipped":0,"pct":0},"branches":{"total":4,"covered":0,"skipped":0,"pct":0}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\enum\\hasAnyFlag.ts": {"lines":{"total":3,"covered":3,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":3,"covered":3,"skipped":0,"pct":100},"branches":{"total":1,"covered":0,"skipped":0,"pct":0}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\enum\\hasFlag.ts": {"lines":{"total":3,"covered":3,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":3,"covered":3,"skipped":0,"pct":100},"branches":{"total":1,"covered":0,"skipped":0,"pct":0}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\enum\\index.ts": {"lines":{"total":14,"covered":0,"skipped":0,"pct":0},"functions":{"total":7,"covered":0,"skipped":0,"pct":0},"statements":{"total":14,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\enum\\toggleFlag.ts": {"lines":{"total":3,"covered":3,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":3,"covered":3,"skipped":0,"pct":100},"branches":{"total":3,"covered":2,"skipped":0,"pct":66.66}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\file\\index.ts": {"lines":{"total":2,"covered":0,"skipped":0,"pct":0},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":2,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\file\\saveBinaryToDisk.ts": {"lines":{"total":11,"covered":0,"skipped":0,"pct":0},"functions":{"total":2,"covered":0,"skipped":0,"pct":0},"statements":{"total":12,"covered":0,"skipped":0,"pct":0},"branches":{"total":2,"covered":0,"skipped":0,"pct":0}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\guid\\index.ts": {"lines":{"total":2,"covered":0,"skipped":0,"pct":0},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":2,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\guid\\isGuid.ts": {"lines":{"total":4,"covered":4,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":4,"covered":4,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\headers\\extractFilenameFromHeaders.ts": {"lines":{"total":17,"covered":15,"skipped":0,"pct":88.23},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":17,"covered":15,"skipped":0,"pct":88.23},"branches":{"total":15,"covered":14,"skipped":0,"pct":93.33}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\headers\\index.ts": {"lines":{"total":2,"covered":0,"skipped":0,"pct":0},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":2,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\zod\\applyFormBulkChange.ts": {"lines":{"total":3,"covered":0,"skipped":0,"pct":0},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":3,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\zod\\applyFormFieldChange.ts": {"lines":{"total":9,"covered":0,"skipped":0,"pct":0},"functions":{"total":2,"covered":0,"skipped":0,"pct":0},"statements":{"total":10,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\zod\\createFormBulkUpdater.ts": {"lines":{"total":4,"covered":0,"skipped":0,"pct":0},"functions":{"total":2,"covered":0,"skipped":0,"pct":0},"statements":{"total":5,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\zod\\createFormFieldUpdater.ts": {"lines":{"total":4,"covered":0,"skipped":0,"pct":0},"functions":{"total":2,"covered":0,"skipped":0,"pct":0},"statements":{"total":5,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\zod\\emptyFormErrors.ts": {"lines":{"total":3,"covered":3,"skipped":0,"pct":100},"functions":{"total":2,"covered":2,"skipped":0,"pct":100},"statements":{"total":4,"covered":4,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\zod\\flattenFormValidationIssues.ts": {"lines":{"total":7,"covered":7,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":7,"covered":7,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\zod\\index.ts": {"lines":{"total":12,"covered":0,"skipped":0,"pct":0},"functions":{"total":6,"covered":0,"skipped":0,"pct":0},"statements":{"total":12,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\functions\\zod\\validateFormState.ts": {"lines":{"total":7,"covered":7,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":7,"covered":7,"skipped":0,"pct":100},"branches":{"total":2,"covered":2,"skipped":0,"pct":100}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\http\\authInterceptors.ts": {"lines":{"total":60,"covered":0,"skipped":0,"pct":0},"functions":{"total":9,"covered":0,"skipped":0,"pct":0},"statements":{"total":60,"covered":0,"skipped":0,"pct":0},"branches":{"total":38,"covered":0,"skipped":0,"pct":0}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\http\\config.ts": {"lines":{"total":18,"covered":0,"skipped":0,"pct":0},"functions":{"total":4,"covered":0,"skipped":0,"pct":0},"statements":{"total":18,"covered":0,"skipped":0,"pct":0},"branches":{"total":13,"covered":0,"skipped":0,"pct":0}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\http\\createWebUiHttpClient.ts": {"lines":{"total":49,"covered":0,"skipped":0,"pct":0},"functions":{"total":22,"covered":0,"skipped":0,"pct":0},"statements":{"total":50,"covered":0,"skipped":0,"pct":0},"branches":{"total":15,"covered":0,"skipped":0,"pct":0}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\http\\errorHandler.ts": {"lines":{"total":12,"covered":0,"skipped":0,"pct":0},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":12,"covered":0,"skipped":0,"pct":0},"branches":{"total":13,"covered":0,"skipped":0,"pct":0}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\http\\formData.ts": {"lines":{"total":9,"covered":0,"skipped":0,"pct":0},"functions":{"total":3,"covered":0,"skipped":0,"pct":0},"statements":{"total":10,"covered":0,"skipped":0,"pct":0},"branches":{"total":4,"covered":0,"skipped":0,"pct":0}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\http\\index.ts": {"lines":{"total":5,"covered":0,"skipped":0,"pct":0},"functions":{"total":5,"covered":0,"skipped":0,"pct":0},"statements":{"total":10,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\http\\problemDetails.ts": {"lines":{"total":5,"covered":5,"skipped":0,"pct":100},"functions":{"total":3,"covered":3,"skipped":0,"pct":100},"statements":{"total":6,"covered":6,"skipped":0,"pct":100},"branches":{"total":9,"covered":8,"skipped":0,"pct":88.88}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\localStorage\\identity.ts": {"lines":{"total":9,"covered":0,"skipped":0,"pct":0},"functions":{"total":3,"covered":0,"skipped":0,"pct":0},"statements":{"total":12,"covered":0,"skipped":0,"pct":0},"branches":{"total":2,"covered":0,"skipped":0,"pct":0}} +,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\signalr\\useWebUiHub.ts": {"lines":{"total":61,"covered":10,"skipped":0,"pct":16.39},"functions":{"total":12,"covered":1,"skipped":0,"pct":8.33},"statements":{"total":64,"covered":12,"skipped":0,"pct":18.75},"branches":{"total":33,"covered":7,"skipped":0,"pct":21.21}} ,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\types\\ScopePermissions.ts": {"lines":{"total":6,"covered":6,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":6,"covered":6,"skipped":0,"pct":100},"branches":{"total":2,"covered":2,"skipped":0,"pct":100}} -,"E:\\Users\\maksym\\source\\repos\\MaksIT\\maksit-webui\\src\\packages\\core\\src\\types\\index.ts": {"lines":{"total":1,"covered":0,"skipped":0,"pct":0},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":2,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} } diff --git a/src/jest.config.cjs b/src/jest.config.cjs index 45c8c1a..67bab30 100644 --- a/src/jest.config.cjs +++ b/src/jest.config.cjs @@ -2,12 +2,11 @@ module.exports = { preset: 'ts-jest', testEnvironment: 'node', - roots: ['/packages/core/src', '/packages/contracts/src'], + roots: ['/packages/core/test', '/packages/contracts/test'], testMatch: ['**/*.test.ts'], collectCoverageFrom: [ 'packages/core/src/**/*.ts', 'packages/contracts/src/**/*.ts', - '!**/*.test.ts', ], coverageDirectory: 'coverage', coverageReporters: ['json-summary', 'text'], diff --git a/src/package-lock.json b/src/package-lock.json index 32041b5..814d4fb 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,12 +1,12 @@ { "name": "maksit-webui", - "version": "0.3.2", + "version": "0.3.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "maksit-webui", - "version": "0.3.2", + "version": "0.3.3", "license": "MIT", "workspaces": [ "packages/*" @@ -36,6 +36,7 @@ "storybook": "^10.4.1", "tailwindcss": "^4.3.0", "ts-jest": "^29.4.11", + "tsup": "^8.5.1", "vite": "^6.4.2", "vitest": "^4.1.7" }, @@ -51,13 +52,13 @@ "license": "MIT" }, "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -65,10 +66,17 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/code-frame/node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@babel/compat-data": { - "version": "7.29.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz", - "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "dev": true, "license": "MIT", "engines": { @@ -76,22 +84,22 @@ } }, "node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -108,14 +116,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -125,14 +133,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -142,9 +150,9 @@ } }, "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "dev": true, "license": "MIT", "engines": { @@ -152,29 +160,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -184,9 +192,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", - "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", "dev": true, "license": "MIT", "engines": { @@ -194,9 +202,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "dev": true, "license": "MIT", "engines": { @@ -204,9 +212,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "dev": true, "license": "MIT", "engines": { @@ -214,9 +222,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "dev": true, "license": "MIT", "engines": { @@ -224,27 +232,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", - "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", - "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -309,13 +317,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", - "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -351,13 +359,13 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", - "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -477,13 +485,13 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", - "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -493,9 +501,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", - "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", "dev": true, "license": "MIT", "engines": { @@ -503,33 +511,33 @@ } }, "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", "debug": "^4.3.1" }, "engines": { @@ -537,25 +545,28 @@ } }, "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/@blazediff/core": { "version": "1.9.1", @@ -1018,27 +1029,27 @@ } }, "node_modules/@inquirer/ansi": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.5.tgz", - "integrity": "sha512-doc2sWgJpbFQ64UflSVd17ibMGDuxO1yKgOgLMwavzESnXjFWJqUeG8saYosqKpHp4kWiM5x1nXvEjbpx90gzw==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.7.tgz", + "integrity": "sha512-3eTuUO1vH2cZm2ZKHeQxnOqlTi9EfZDGgIe3BL3I4u+rJHocr9Fz86M4fjYABPvFnQG/gGK551HqDiIcETwU6Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" } }, "node_modules/@inquirer/confirm": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.0.13.tgz", - "integrity": "sha512-wkGPC7yJ5WJk1DJ5SX7fzk+gfj4BM8cf5dDDi71B/551xHrdsZVRJOC0WyikXd0pEsb/9cLniuE4atbsMqmFkw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.1.1.tgz", + "integrity": "sha512-eb8DBZcz/2qHWQda4rk2JiQk5h9QV/cVHi1yjt0f69WFZMRFn0sJTye3EAP8icut8UDMjQPsaH5KbcOogefrFQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.10", - "@inquirer/type": "^4.0.5" + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1050,22 +1061,22 @@ } }, "node_modules/@inquirer/core": { - "version": "11.1.10", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.1.10.tgz", - "integrity": "sha512-a4Q5BXHQAHa9eO202sTaFCHFYVB3x5fauDuThEAdZ9gfn76pSxiKU7wWcEH0N1O0XmQvNfQNU6QXpiRxmYQx+A==", + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.2.1.tgz", + "integrity": "sha512-Qd6GJT1yVyrZZCfN8W2qKF5ApmqryXRhRKCuip8h01x2w/esJQ2XIYc6f9abMIHgKQdBfFTSOdbHRLAhuM09UA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.5", - "@inquirer/figures": "^2.0.5", - "@inquirer/type": "^4.0.5", + "@inquirer/ansi": "^2.0.7", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7", "cli-width": "^4.1.0", "fast-wrap-ansi": "^0.2.0", "mute-stream": "^3.0.0", "signal-exit": "^4.1.0" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1090,23 +1101,23 @@ } }, "node_modules/@inquirer/figures": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.5.tgz", - "integrity": "sha512-NsSs4kzfm12lNetHwAn3GEuH317IzpwrMCbOuMIVytpjnJ90YYHNwdRgYGuKmVxwuIqSgqk3M5qqQt1cDk0tGQ==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.7.tgz", + "integrity": "sha512-aJ8TBPOGB6f/2qziPfElISTCEd5XOYTFckA2SGjhNmiKzfK/u4ot3v0DUzGVdUnKjN10EqnnEPck36BkyfLnJw==", "dev": true, "license": "MIT", "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" } }, "node_modules/@inquirer/type": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.5.tgz", - "integrity": "sha512-aetVUNeKNc/VriqXlw1NRSW0zhMBB0W4bNbWRJgzRl/3d0QNDQFfk0GO5SDdtjMZVg6o8ZKEiadd7SCCzoOn5Q==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.7.tgz", + "integrity": "sha512-t28inv14nMQ1PhKpsJPY+kEs/c00qzeCOS2gTNRyTjG5d6qsVA2fItxW4hkvGZ5lvanGLdtCzVIx5dwdRpN1+g==", "dev": true, "license": "MIT", "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1364,6 +1375,13 @@ } } }, + "node_modules/@jest/reporters/node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, "node_modules/@jest/schemas": { "version": "30.4.1", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", @@ -1585,6 +1603,42 @@ "react": ">=16" } }, + "node_modules/@microsoft/signalr": { + "version": "8.0.17", + "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-8.0.17.tgz", + "integrity": "sha512-5pM6xPtKZNJLO0Tq5nQasVyPFwi/WBY3QB5uc/v3dIPTpS1JXQbaXAQAPxFoQ5rTBFE094w8bbqkp17F9ReQvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "eventsource": "^2.0.2", + "fetch-cookie": "^2.0.3", + "node-fetch": "^2.6.7", + "ws": "^7.5.10" + } + }, + "node_modules/@microsoft/signalr/node_modules/ws": { + "version": "7.5.11", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", + "integrity": "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/@mswjs/interceptors": { "version": "0.41.9", "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.41.9.tgz", @@ -2030,9 +2084,9 @@ } }, "node_modules/@oxc-resolver/binding-android-arm-eabi": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm-eabi/-/binding-android-arm-eabi-11.19.1.tgz", - "integrity": "sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm-eabi/-/binding-android-arm-eabi-11.20.0.tgz", + "integrity": "sha512-IjfWOXRgJFNdORDl+Uf1aibNgZY2guOD3zmOhx1BGVb/MIiqlFTdmjpQNplSN58lhWehnX4UNqC3QwpUo8pjJg==", "cpu": [ "arm" ], @@ -2044,9 +2098,9 @@ ] }, "node_modules/@oxc-resolver/binding-android-arm64": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm64/-/binding-android-arm64-11.19.1.tgz", - "integrity": "sha512-oolbkRX+m7Pq2LNjr/kKgYeC7bRDMVTWPgxBGMjSpZi/+UskVo4jsMU3MLheZV55jL6c3rNelPl4oD60ggYmqA==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm64/-/binding-android-arm64-11.20.0.tgz", + "integrity": "sha512-QqslZAuFQG8Q9xm7JuIn8JUbvywhSBMVhuQHtYW+auirZJloS41oxUUaBXk7uUhZJgp44c5zQLeVvmFaDQB+2Q==", "cpu": [ "arm64" ], @@ -2058,9 +2112,9 @@ ] }, "node_modules/@oxc-resolver/binding-darwin-arm64": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-11.19.1.tgz", - "integrity": "sha512-nUC6d2i3R5B12sUW4O646qD5cnMXf2oBGPLIIeaRfU9doJRORAbE2SGv4eW6rMqhD+G7nf2Y8TTJTLiiO3Q/dQ==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-11.20.0.tgz", + "integrity": "sha512-MUcavykj2ewlR+kc5arpg4tC2RvzJkUxWtNv74pf7lcNk00GpIpN43vXMj+j6r4eMmfZhlb8hueKoIb8e9kAGQ==", "cpu": [ "arm64" ], @@ -2072,9 +2126,9 @@ ] }, "node_modules/@oxc-resolver/binding-darwin-x64": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-11.19.1.tgz", - "integrity": "sha512-cV50vE5+uAgNcFa3QY1JOeKDSkM/9ReIcc/9wn4TavhW/itkDGrXhw9jaKnkQnGbjJ198Yh5nbX/Gr2mr4Z5jQ==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-11.20.0.tgz", + "integrity": "sha512-BGB16nRUK5Etiv//ihPyzj8Lj1px0mhh4YIfe0FDf045ywknfSm0GEbiRESpr6Q4K82AvnyaRIhhluHByvS4bg==", "cpu": [ "x64" ], @@ -2086,9 +2140,9 @@ ] }, "node_modules/@oxc-resolver/binding-freebsd-x64": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-11.19.1.tgz", - "integrity": "sha512-xZOQiYGFxtk48PBKff+Zwoym7ScPAIVp4c14lfLxizO2LTTTJe5sx9vQNGrBymrf/vatSPNMD4FgsaaRigPkqw==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-11.20.0.tgz", + "integrity": "sha512-JZgtePaqj3qmD5XFHJaSLWzHRxQu0LaPkdoM1KJXYADvAaa83ijXHclV3ej3CueeW0wxfIAbGCZVP45J0CA7uQ==", "cpu": [ "x64" ], @@ -2100,9 +2154,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm-gnueabihf": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-11.19.1.tgz", - "integrity": "sha512-lXZYWAC6kaGe/ky2su94e9jN9t6M0/6c+GrSlCqL//XO1cxi5lpAhnJYdyrKfm0ZEr/c7RNyAx3P7FSBcBd5+A==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-11.20.0.tgz", + "integrity": "sha512-hOQ/p3ry3v3SchUBXicrrnszaI/UmYzM4wtS4RGfwgVUX7a+HbyQSzJ5aOzu+o6XZkFkS3ZXN4PZAzhOb77OSg==", "cpu": [ "arm" ], @@ -2114,9 +2168,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm-musleabihf": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-11.19.1.tgz", - "integrity": "sha512-veG1kKsuK5+t2IsO9q0DErYVSw2azvCVvWHnfTOS73WE0STdLLB7Q1bB9WR+yHPQM76ASkFyRbogWo1GR1+WbQ==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-11.20.0.tgz", + "integrity": "sha512-2ArPksaw0AqeuGBfoS715VF+JvJQAhD2niWgjE5hVO+L+nAfikVQopvngCMX9x4BD8itWoQ3dnikrQyl5Ho5Jg==", "cpu": [ "arm" ], @@ -2128,9 +2182,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm64-gnu": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.19.1.tgz", - "integrity": "sha512-heV2+jmXyYnUrpUXSPugqWDRpnsQcDm2AX4wzTuvgdlZfoNYO0O3W2AVpJYaDn9AG4JdM6Kxom8+foE7/BcSig==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.20.0.tgz", + "integrity": "sha512-0bJnmYFp62JdZ4nVMDUZ/C58BCZOCcqgKtnUlp7L9Ojf/czIN+3j72YlLPeWLkzlr6SlYvIQA4SGV/HyO0d+qg==", "cpu": [ "arm64" ], @@ -2142,9 +2196,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm64-musl": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.19.1.tgz", - "integrity": "sha512-jvo2Pjs1c9KPxMuMPIeQsgu0mOJF9rEb3y3TdpsrqwxRM+AN6/nDDwv45n5ZrUnQMsdBy5gIabioMKnQfWo9ew==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.20.0.tgz", + "integrity": "sha512-wKHHzPKZo7Ufhv/Bt6yxT7FOgnIgW4gwXcJUipkShGp68W3wGVqvr1Sr0fY65lN0Oy6y41+g2kIDvkgZaMMUkw==", "cpu": [ "arm64" ], @@ -2156,9 +2210,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-ppc64-gnu": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-11.19.1.tgz", - "integrity": "sha512-vLmdNxWCdN7Uo5suays6A/+ywBby2PWBBPXctWPg5V0+eVuzsJxgAn6MMB4mPlshskYbppjpN2Zg83ArHze9gQ==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-11.20.0.tgz", + "integrity": "sha512-RN8goF7Ie0B79L4i4G6OeBocTgSC56vJbQ65VJje+oXnldVpLnOU7j/AQ/dP94TcCS+Yh6WG8u3Qt4ETteXFNQ==", "cpu": [ "ppc64" ], @@ -2170,9 +2224,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-riscv64-gnu": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.19.1.tgz", - "integrity": "sha512-/b+WgR+VTSBxzgOhDO7TlMXC1ufPIMR6Vj1zN+/x+MnyXGW7prTLzU9eW85Aj7Th7CCEG9ArCbTeqxCzFWdg2w==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.20.0.tgz", + "integrity": "sha512-5l1yU6/xQEqLZRzxqmMxJfWPslpwCmBsdDGaBvABPehxquCXDC7dd7oraNdKSJUMDXSM7VvVj8H2D2FTjU7oWw==", "cpu": [ "riscv64" ], @@ -2184,9 +2238,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-riscv64-musl": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-11.19.1.tgz", - "integrity": "sha512-YlRdeWb9j42p29ROh+h4eg/OQ3dTJlpHSa+84pUM9+p6i3djtPz1q55yLJhgW9XfDch7FN1pQ/Vd6YP+xfRIuw==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-11.20.0.tgz", + "integrity": "sha512-xHEvkbgz6UC+A3JOyDQy76LkUaxsNSfIr3/GV8slwZsnuooJiIB34gzJfsyvR4JdCYNUUPsRJc/w/oWkODu+hg==", "cpu": [ "riscv64" ], @@ -2198,9 +2252,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-s390x-gnu": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.19.1.tgz", - "integrity": "sha512-EDpafVOQWF8/MJynsjOGFThcqhRHy417sRyLfQmeiamJ8qVhSKAn2Dn2VVKUGCjVB9C46VGjhNo7nOPUi1x6uA==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.20.0.tgz", + "integrity": "sha512-aWPDUUmSeyHvlW+SoEUd+JIJsQhVhu6a5tBpDRMu058naPAchTgAVGCFy35zjbnFlt0i8hLWziff6HX0D3LU4g==", "cpu": [ "s390x" ], @@ -2212,9 +2266,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-x64-gnu": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.19.1.tgz", - "integrity": "sha512-NxjZe+rqWhr+RT8/Ik+5ptA3oz7tUw361Wa5RWQXKnfqwSSHdHyrw6IdcTfYuml9dM856AlKWZIUXDmA9kkiBQ==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.20.0.tgz", + "integrity": "sha512-x2YeSimvhJjKLVD8KSu8f/rqU1potcdEMkApIPJqjZWN7c2Fpt4g2X32WDg1p+XDAmyT7nuQGe0vnhvXeLbH+g==", "cpu": [ "x64" ], @@ -2226,9 +2280,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-x64-musl": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.19.1.tgz", - "integrity": "sha512-cM/hQwsO3ReJg5kR+SpI69DMfvNCp+A/eVR4b4YClE5bVZwz8rh2Nh05InhwI5HR/9cArbEkzMjcKgTHS6UaNw==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.20.0.tgz", + "integrity": "sha512-kcRLEIxpZefeYfLChjpgFf3ilBzRDZ+yobMrpRsQlSrxuFGtm3U6PMU7AaEpMqo3NfDGVyJJseAjnRLzMFHjwQ==", "cpu": [ "x64" ], @@ -2240,9 +2294,9 @@ ] }, "node_modules/@oxc-resolver/binding-openharmony-arm64": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-openharmony-arm64/-/binding-openharmony-arm64-11.19.1.tgz", - "integrity": "sha512-QF080IowFB0+9Rh6RcD19bdgh49BpQHUW5TajG1qvWHvmrQznTZZjYlgE2ltLXyKY+qs4F/v5xuX1XS7Is+3qA==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-openharmony-arm64/-/binding-openharmony-arm64-11.20.0.tgz", + "integrity": "sha512-HHcfnApSZGtKhTiHqe8OZruOZe5XuFQH5/E0Yhj3u8fnFvzkM4/k6WjacUf4SvA0SPEAbfbgYmVPuo0VX/fIBQ==", "cpu": [ "arm64" ], @@ -2254,9 +2308,9 @@ ] }, "node_modules/@oxc-resolver/binding-wasm32-wasi": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-11.19.1.tgz", - "integrity": "sha512-w8UCKhX826cP/ZLokXDS6+milN8y4X7zidsAttEdWlVoamTNf6lhBJldaWr3ukTDiye7s4HRcuPEPOXNC432Vg==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-11.20.0.tgz", + "integrity": "sha512-Tn0y1XOFYHNfK1wp1Z5QK8Rcld/bsOwRISQXfqAZ5IBpv8Gz1IvV39fUWNprqNdRizgcvFhOzWwFun2zkJsyBg==", "cpu": [ "wasm32" ], @@ -2264,16 +2318,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.1.1" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@oxc-resolver/binding-win32-arm64-msvc": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-11.19.1.tgz", - "integrity": "sha512-nJ4AsUVZrVKwnU/QRdzPCCrO0TrabBqgJ8pJhXITdZGYOV28TIYystV1VFLbQ7DtAcaBHpocT5/ZJnF78YJPtQ==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-11.20.0.tgz", + "integrity": "sha512-qPi25YNPe4YenS8MgsQU2+bIFHxxpLx1LVna2444cEHqNPhNjvWf9zqj4aWE43H9LpAsTmkkAlA3eL5ElBU3mA==", "cpu": [ "arm64" ], @@ -2284,24 +2340,10 @@ "win32" ] }, - "node_modules/@oxc-resolver/binding-win32-ia32-msvc": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-11.19.1.tgz", - "integrity": "sha512-EW+ND5q2Tl+a3pH81l1QbfgbF3HmqgwLfDfVithRFheac8OTcnbXt/JxqD2GbDkb7xYEqy1zNaVFRr3oeG8npA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@oxc-resolver/binding-win32-x64-msvc": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-11.19.1.tgz", - "integrity": "sha512-6hIU3RQu45B+VNTY4Ru8ppFwjVS/S5qwYyGhBotmjxfEKk41I2DlGtRfGJndZ5+6lneE2pwloqunlOyZuX/XAw==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-11.20.0.tgz", + "integrity": "sha512-Wb14jWEW8huH6It9F6sXd9vrYmIS7pMrgkU6sxpLxkP+9z+wRgs71hUEhRpcn8FOXAFa27FVWfY2tRpbfTzfLw==", "cpu": [ "x64" ], @@ -2313,13 +2355,13 @@ ] }, "node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.3.6.tgz", + "integrity": "sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==", "dev": true, "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + "node": "^14.18.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/pkgr" @@ -2333,9 +2375,9 @@ "license": "MIT" }, "node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", + "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", "dev": true, "license": "MIT", "dependencies": { @@ -3207,6 +3249,51 @@ "node": ">=14.0.0" } }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": { + "version": "2.8.1", + "dev": true, + "inBundle": true, + "license": "0BSD", + "optional": true + }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.0.tgz", @@ -3339,13 +3426,6 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@testing-library/dom/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true, - "license": "MIT" - }, "node_modules/@testing-library/jest-dom": { "version": "6.9.1", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", @@ -3476,9 +3556,9 @@ "license": "MIT" }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "dev": true, "license": "MIT" }, @@ -3999,60 +4079,13 @@ } } }, - "node_modules/@vitest/browser-playwright/node_modules/tinyrainbow": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@vitest/browser/node_modules/@vitest/pretty-format": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.7.tgz", - "integrity": "sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/browser/node_modules/@vitest/utils": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.7.tgz", - "integrity": "sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.7", - "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/browser/node_modules/tinyrainbow": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@vitest/coverage-v8": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.7.tgz", "integrity": "sha512-qsYPeXc5Q9dFLd1i8Ap+Bx8sQgcp+rFVQo4R0dDsWNBzl26ldVF1qOO+RL24K7FDrR6pA+50XedRLSoSG24bVQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@bcoe/v8-coverage": "^1.0.2", "@vitest/utils": "4.1.7", @@ -4078,54 +4111,6 @@ } } }, - "node_modules/@vitest/coverage-v8/node_modules/@bcoe/v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", - "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@vitest/coverage-v8/node_modules/@vitest/pretty-format": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.7.tgz", - "integrity": "sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/coverage-v8/node_modules/@vitest/utils": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.7.tgz", - "integrity": "sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.7", - "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/coverage-v8/node_modules/tinyrainbow": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@vitest/expect": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", @@ -4143,6 +4128,57 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@vitest/expect/node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/expect/node_modules/@vitest/spy": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/expect/node_modules/@vitest/utils": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/expect/node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@vitest/mocker": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.7.tgz", @@ -4170,16 +4206,6 @@ } } }, - "node_modules/@vitest/mocker/node_modules/@vitest/spy": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.7.tgz", - "integrity": "sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" - } - }, "node_modules/@vitest/mocker/node_modules/estree-walker": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", @@ -4191,13 +4217,13 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", - "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.7.tgz", + "integrity": "sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==", "dev": true, "license": "MIT", "dependencies": { - "tinyrainbow": "^2.0.0" + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" @@ -4218,44 +4244,6 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/runner/node_modules/@vitest/pretty-format": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.7.tgz", - "integrity": "sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner/node_modules/@vitest/utils": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.7.tgz", - "integrity": "sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.7", - "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner/node_modules/tinyrainbow": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@vitest/snapshot": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.7.tgz", @@ -4272,20 +4260,17 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/snapshot/node_modules/@vitest/pretty-format": { + "node_modules/@vitest/spy": { "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.7.tgz", - "integrity": "sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.7.tgz", + "integrity": "sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q==", "dev": true, "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.1.0" - }, "funding": { "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/snapshot/node_modules/@vitest/utils": { + "node_modules/@vitest/utils": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.7.tgz", "integrity": "sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==", @@ -4300,44 +4285,6 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/snapshot/node_modules/tinyrainbow": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@vitest/spy": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", - "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyspy": "^4.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", - "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "3.2.4", - "loupe": "^3.1.4", - "tinyrainbow": "^2.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, "node_modules/@webcontainer/env": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@webcontainer/env/-/env-1.1.1.tgz", @@ -4345,6 +4292,19 @@ "dev": true, "license": "MIT" }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/acorn": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", @@ -4491,9 +4451,9 @@ } }, "node_modules/ast-v8-to-istanbul": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.2.tgz", - "integrity": "sha512-dKmJxJsGItLmc5CYZKuEjuG6GnBs6PG4gohMhyFOWKaNQoYCuRZJDECaBlHmcG0lv2wc2E0uU8lESmBEumC3DQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.3.tgz", + "integrity": "sha512-jCMQ6ZylLPudp0CDfBmQBZUsrh1/8psbmu9ibeVWKuHWD0YrH9YABwlKu5kVEFoT0GCQQW9Z/SxfuEbbkGQCRg==", "dev": true, "license": "MIT", "dependencies": { @@ -4512,13 +4472,6 @@ "@types/estree": "^1.0.0" } }, - "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", - "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", - "dev": true, - "license": "MIT" - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -4659,9 +4612,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.10.32", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.32.tgz", - "integrity": "sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==", + "version": "2.10.33", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.33.tgz", + "integrity": "sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4964,24 +4917,6 @@ "node": ">=12" } }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/clsx": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", @@ -5121,9 +5056,9 @@ "license": "MIT" }, "node_modules/date-fns": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.3.0.tgz", - "integrity": "sha512-OYcL+3N/jyWbYdFGqoMAhytDgxP9pbYPUUiRCOgn4Fewaadk9l/Wam4Avciiyp2BgkpfQyBV9B+ehnVJych+eQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.4.0.tgz", + "integrity": "sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==", "license": "MIT", "funding": { "type": "github", @@ -5313,9 +5248,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.361", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.361.tgz", - "integrity": "sha512-Q6Hts7N9FnJc5LeGRINFvLhCI9xZmNtTDe5ZbcVezQz7cU4a8Aua3GH1b8J2XY8Al9PF+OCwYqhgsOOheMdvkA==", + "version": "1.5.364", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.364.tgz", + "integrity": "sha512-G/dYE3+AYhyHwzTwg8UbnXf7zqMERYh7l2jJ3QujhFsH8agSYwtnGAR2aZ7f0AakIKJXd5En/Hre4igIUrdlYw==", "dev": true, "license": "ISC" }, @@ -5350,9 +5285,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.22.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.0.tgz", - "integrity": "sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A==", + "version": "5.22.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.1.tgz", + "integrity": "sha512-6QEuw3zoX1SJQc7b87aBXke/no+mG2bTBgw29gWMQonLmpEkWoCAVkl+M49e48AZlWzxiDzDZzYdp6kobcyLww==", "dev": true, "license": "MIT", "dependencies": { @@ -5523,6 +5458,26 @@ "node": ">=0.10.0" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -5647,6 +5602,40 @@ } } }, + "node_modules/fetch-cookie": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-2.2.0.tgz", + "integrity": "sha512-h9AgfjURuCgA2+2ISl8GbavpUdR+WGAM2McW/ovn4tVccegp8ZqCKWSBR8uRdM8dDNlx5WdKRWxBYUwteLDCNQ==", + "dev": true, + "license": "Unlicense", + "dependencies": { + "set-cookie-parser": "^2.4.8", + "tough-cookie": "^4.0.0" + } + }, + "node_modules/fetch-cookie/node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fetch-cookie/node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -5888,16 +5877,6 @@ "uglify-js": "^3.1.4" } }, - "node_modules/handlebars/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -5938,9 +5917,9 @@ } }, "node_modules/hasown": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", - "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", "dev": true, "license": "MIT", "dependencies": { @@ -5961,13 +5940,6 @@ "set-cookie-parser": "^3.0.1" } }, - "node_modules/headers-polyfill/node_modules/set-cookie-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.0.tgz", - "integrity": "sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==", - "dev": true, - "license": "MIT" - }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -6844,7 +6816,6 @@ "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "jiti": "lib/jiti-cli.mjs" } @@ -6860,9 +6831,9 @@ } }, "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", "dev": true, "license": "MIT" }, @@ -7247,6 +7218,13 @@ "loose-envify": "cli.js" } }, + "node_modules/loose-envify/node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/loupe": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", @@ -7265,9 +7243,9 @@ } }, "node_modules/lucide-react": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.16.0.tgz", - "integrity": "sha512-dYwyPzb4MEKpGUmNYk3WKWPnMrHs3FKM+q94kAnJrcDIqqn1hq2xY8scaS2ovsOCM5D51ey2gaRG3PBb1vgoYQ==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.17.0.tgz", + "integrity": "sha512-9FA9evdox/JQL5PT57fdA1x/yg8T7knJ98+zjTL3UfKza6pflQUUh3XtaQIHKvnsJw1lmsEyHVlt5jchYxOQ5w==", "dev": true, "license": "ISC", "peerDependencies": { @@ -7631,6 +7609,27 @@ "dev": true, "license": "MIT" }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -7773,35 +7772,34 @@ } }, "node_modules/oxc-resolver": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-11.19.1.tgz", - "integrity": "sha512-qE/CIg/spwrTBFt5aKmwe3ifeDdLfA2NESN30E42X/lII5ClF8V7Wt6WIJhcGZjp0/Q+nQ+9vgxGk//xZNX2hg==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-11.20.0.tgz", + "integrity": "sha512-CblytBiV/a/ZXY34dsVU2NxhIOxMXst8CvDCtyBelVITgd7PLrKzbEbA6oKLdPjvDKDzCiW48qzmzZ+mYaqn+g==", "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/Boshen" }, "optionalDependencies": { - "@oxc-resolver/binding-android-arm-eabi": "11.19.1", - "@oxc-resolver/binding-android-arm64": "11.19.1", - "@oxc-resolver/binding-darwin-arm64": "11.19.1", - "@oxc-resolver/binding-darwin-x64": "11.19.1", - "@oxc-resolver/binding-freebsd-x64": "11.19.1", - "@oxc-resolver/binding-linux-arm-gnueabihf": "11.19.1", - "@oxc-resolver/binding-linux-arm-musleabihf": "11.19.1", - "@oxc-resolver/binding-linux-arm64-gnu": "11.19.1", - "@oxc-resolver/binding-linux-arm64-musl": "11.19.1", - "@oxc-resolver/binding-linux-ppc64-gnu": "11.19.1", - "@oxc-resolver/binding-linux-riscv64-gnu": "11.19.1", - "@oxc-resolver/binding-linux-riscv64-musl": "11.19.1", - "@oxc-resolver/binding-linux-s390x-gnu": "11.19.1", - "@oxc-resolver/binding-linux-x64-gnu": "11.19.1", - "@oxc-resolver/binding-linux-x64-musl": "11.19.1", - "@oxc-resolver/binding-openharmony-arm64": "11.19.1", - "@oxc-resolver/binding-wasm32-wasi": "11.19.1", - "@oxc-resolver/binding-win32-arm64-msvc": "11.19.1", - "@oxc-resolver/binding-win32-ia32-msvc": "11.19.1", - "@oxc-resolver/binding-win32-x64-msvc": "11.19.1" + "@oxc-resolver/binding-android-arm-eabi": "11.20.0", + "@oxc-resolver/binding-android-arm64": "11.20.0", + "@oxc-resolver/binding-darwin-arm64": "11.20.0", + "@oxc-resolver/binding-darwin-x64": "11.20.0", + "@oxc-resolver/binding-freebsd-x64": "11.20.0", + "@oxc-resolver/binding-linux-arm-gnueabihf": "11.20.0", + "@oxc-resolver/binding-linux-arm-musleabihf": "11.20.0", + "@oxc-resolver/binding-linux-arm64-gnu": "11.20.0", + "@oxc-resolver/binding-linux-arm64-musl": "11.20.0", + "@oxc-resolver/binding-linux-ppc64-gnu": "11.20.0", + "@oxc-resolver/binding-linux-riscv64-gnu": "11.20.0", + "@oxc-resolver/binding-linux-riscv64-musl": "11.20.0", + "@oxc-resolver/binding-linux-s390x-gnu": "11.20.0", + "@oxc-resolver/binding-linux-x64-gnu": "11.20.0", + "@oxc-resolver/binding-linux-x64-musl": "11.20.0", + "@oxc-resolver/binding-openharmony-arm64": "11.20.0", + "@oxc-resolver/binding-wasm32-wasi": "11.20.0", + "@oxc-resolver/binding-win32-arm64-msvc": "11.20.0", + "@oxc-resolver/binding-win32-x64-msvc": "11.20.0" } }, "node_modules/p-limit": { @@ -7923,9 +7921,9 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "11.5.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.0.tgz", - "integrity": "sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA==", + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -8182,6 +8180,13 @@ "react-is": "^16.13.1" } }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, "node_modules/proxy-from-env": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", @@ -8192,6 +8197,29 @@ "node": ">=10" } }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/pure-rand": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", @@ -8209,6 +8237,13 @@ ], "license": "MIT" }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true, + "license": "MIT" + }, "node_modules/react": { "version": "19.2.6", "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", @@ -8267,9 +8302,9 @@ } }, "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true, "license": "MIT" }, @@ -8297,9 +8332,9 @@ "license": "MIT" }, "node_modules/react-router": { - "version": "7.15.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.15.1.tgz", - "integrity": "sha512-R8rl9HhgikFYoPJymnUtPXWbnDb3oget6lQnfIoupbt61aT9aOhRkDsY2XRhZRyX1Z/8a5sL74fXmFNm3NRK5A==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.16.0.tgz", + "integrity": "sha512-wArC8lVyJb3+jM9OpDyW6hLCizACWkvQR/sSGqSs+o5uEXEtGlqdZ4v8hENR3Jad6i+LRkK93q/+bQAcvl6V1A==", "dev": true, "license": "MIT", "dependencies": { @@ -8320,13 +8355,13 @@ } }, "node_modules/react-router-dom": { - "version": "7.15.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.15.1.tgz", - "integrity": "sha512-AzF62gjY6U9rkMq4RfP/r2EVtQ7DMfNMjyOp/flLTCrtRylLiK4wT4pSq6O8rOXZ2eXdZYJPEYe+ifomiv+Igg==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.16.0.tgz", + "integrity": "sha512-kMUAbimWB5FVbF4Bce4bJsiKJWLIUHq/mEG8+CFDnCSgltptBiG5nguducmsJeGKytlCvQud9Qhzpn49iduTlA==", "dev": true, "license": "MIT", "dependencies": { - "react-router": "7.15.1" + "react-router": "7.16.0" }, "engines": { "node": ">=20.0.0" @@ -8336,6 +8371,13 @@ "react-dom": ">=18" } }, + "node_modules/react-router/node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "dev": true, + "license": "MIT" + }, "node_modules/react-virtualized": { "version": "9.22.6", "resolved": "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.22.6.tgz", @@ -8386,16 +8428,6 @@ "node": ">= 4" } }, - "node_modules/recast/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -8433,6 +8465,13 @@ "node": ">=0.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.12", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", @@ -8491,6 +8530,7 @@ "integrity": "sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -8530,6 +8570,13 @@ "fsevents": "~2.3.2" } }, + "node_modules/rollup/node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, "node_modules/run-applescript": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", @@ -8561,9 +8608,9 @@ } }, "node_modules/set-cookie-parser": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", - "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.0.tgz", + "integrity": "sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==", "dev": true, "license": "MIT" }, @@ -8630,13 +8677,13 @@ } }, "node_modules/source-map": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "license": "BSD-3-Clause", "engines": { - "node": ">= 12" + "node": ">=0.10.0" } }, "node_modules/source-map-js": { @@ -8660,16 +8707,6 @@ "source-map": "^0.6.0" } }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -8762,6 +8799,19 @@ } } }, + "node_modules/storybook/node_modules/@vitest/spy": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/storybook/node_modules/semver": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", @@ -8920,13 +8970,13 @@ } }, "node_modules/synckit": { - "version": "0.11.12", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", - "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.13.tgz", + "integrity": "sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==", "dev": true, "license": "MIT", "dependencies": { - "@pkgr/core": "^0.2.9" + "@pkgr/core": "^0.3.6" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -9029,9 +9079,9 @@ "license": "MIT" }, "node_modules/tinyglobby": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", - "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "dev": true, "license": "MIT", "dependencies": { @@ -9046,9 +9096,9 @@ } }, "node_modules/tinyrainbow": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", - "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", "dev": true, "license": "MIT", "engines": { @@ -9066,22 +9116,22 @@ } }, "node_modules/tldts": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.0.tgz", - "integrity": "sha512-yHBe+zVfzNZ3QfTPW/Z6KK1G2t340gFjMHqI/4KKSt/abzYydzuCnpqdaF5gCCABby+9Yfbj59oR5F2Fd5CBzg==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.2.tgz", + "integrity": "sha512-kCwffuaH8ntKtygnWe1b4BJKWiCUH30n5KfoTr6IchcXOwR7chAOFJxFrH3vjANafUYrIA4a7SDL+nn7SiR4Sw==", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^7.4.0" + "tldts-core": "^7.4.2" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.0.tgz", - "integrity": "sha512-/mb9kRld+x1sIMXxWNOAp5m6C+D4GrAORWlJkOJ5dElvxdN1eutz/o7qHLp9gFvDF4Y3/L2xeScoxz6AbEo8rQ==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.2.tgz", + "integrity": "sha512-nwEyF4vl4RSJjwSjBUmOSxc3BFPoIFdlRthJ6e+5v9P3bHNsoD06UjuqMUspqp7vsEZ1beaHi1km+optiE17yA==", "dev": true, "license": "MIT" }, @@ -9115,6 +9165,13 @@ "node": ">=16" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -9306,6 +9363,16 @@ } } }, + "node_modules/tsup/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -9372,6 +9439,16 @@ "dev": true, "license": "MIT" }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/unplugin": { "version": "2.3.11", "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", @@ -9467,6 +9544,17 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/use-sync-external-store": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", @@ -10161,44 +10249,6 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/vitest/node_modules/@vitest/pretty-format": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.7.tgz", - "integrity": "sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/vitest/node_modules/@vitest/spy": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.7.tgz", - "integrity": "sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/vitest/node_modules/@vitest/utils": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.7.tgz", - "integrity": "sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.7", - "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, "node_modules/vitest/node_modules/chai": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", @@ -10210,25 +10260,15 @@ } }, "node_modules/vitest/node_modules/tinyexec": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.2.tgz", - "integrity": "sha512-M/Q0B2cp4K7kynaT/vnED1j8TlLY+Pp7C6Wl2bl/7u/F0mUVwdyOpwomQb8JpYLitHUssAJRmLZdMCGsrx7i+g==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", "dev": true, "license": "MIT", "engines": { "node": ">=18" } }, - "node_modules/vitest/node_modules/tinyrainbow": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -10239,6 +10279,13 @@ "makeerror": "1.0.12" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/webpack-virtual-modules": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", @@ -10246,6 +10293,17 @@ "dev": true, "license": "MIT" }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -10286,6 +10344,24 @@ "dev": true, "license": "MIT" }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/write-file-atomic": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", @@ -10422,10 +10498,10 @@ }, "packages/components": { "name": "@maks-it.com/webui-components", - "version": "0.3.2", + "version": "0.3.3", "dependencies": { - "@maks-it.com/webui-contracts": "^0.3.2", - "@maks-it.com/webui-core": "^0.3.2" + "@maks-it.com/webui-contracts": "^0.3.3", + "@maks-it.com/webui-core": "^0.3.3" }, "devDependencies": { "@tanstack/react-table": "^8.21.3", @@ -10453,7 +10529,7 @@ }, "packages/contracts": { "name": "@maks-it.com/webui-contracts", - "version": "0.3.2", + "version": "0.3.3", "devDependencies": { "tsup": "^8.5.1", "typescript": "^6.0.3", @@ -10465,12 +10541,13 @@ }, "packages/core": { "name": "@maks-it.com/webui-core", - "version": "0.3.2", + "version": "0.3.3", "dependencies": { - "@maks-it.com/webui-contracts": "^0.3.2", + "@maks-it.com/webui-contracts": "^0.3.3", "date-fns": "^4.3.0" }, "devDependencies": { + "@microsoft/signalr": "^8.0.7", "@types/react": "^19.2.15", "axios": "^1.16.1", "react": "^19.2.6", @@ -10479,6 +10556,7 @@ "zod": "^4.4.3" }, "peerDependencies": { + "@microsoft/signalr": "^8.0.0", "axios": "^1.16.0", "react": "^18.0.0 || ^19.0.0", "zod": "^4.4.0" diff --git a/src/package.json b/src/package.json index e497ec3..7fa016f 100644 --- a/src/package.json +++ b/src/package.json @@ -1,7 +1,7 @@ { "name": "maksit-webui", "private": true, - "version": "0.3.2", + "version": "0.3.3", "description": "Shared React UI library for MaksIT Certs UI and Vault WebUI", "workspaces": [ "packages/*" diff --git a/src/packages/components/package.json b/src/packages/components/package.json index 393126a..bc497f9 100644 --- a/src/packages/components/package.json +++ b/src/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@maks-it.com/webui-components", - "version": "0.3.2", + "version": "0.3.3", "description": "Shared React components for MaksIT WebUI apps", "type": "module", "main": "./dist/index.cjs", @@ -33,8 +33,8 @@ "directory": "src/packages/components" }, "dependencies": { - "@maks-it.com/webui-contracts": "^0.3.2", - "@maks-it.com/webui-core": "^0.3.2" + "@maks-it.com/webui-contracts": "^0.3.3", + "@maks-it.com/webui-core": "^0.3.3" }, "peerDependencies": { "@tanstack/react-table": "^8.0.0", diff --git a/src/packages/contracts/package.json b/src/packages/contracts/package.json index f01eb7c..2c95509 100644 --- a/src/packages/contracts/package.json +++ b/src/packages/contracts/package.json @@ -1,6 +1,6 @@ { "name": "@maks-it.com/webui-contracts", - "version": "0.3.2", + "version": "0.3.3", "description": "Shared TypeScript contracts for MaksIT WebUI apps", "type": "module", "main": "./dist/index.cjs", diff --git a/src/packages/contracts/src/schemas.test.ts b/src/packages/contracts/test/schemas.test.ts similarity index 83% rename from src/packages/contracts/src/schemas.test.ts rename to src/packages/contracts/test/schemas.test.ts index 2d87b77..ab55bd8 100644 --- a/src/packages/contracts/src/schemas.test.ts +++ b/src/packages/contracts/test/schemas.test.ts @@ -1,8 +1,8 @@ -import { PatchOperation } from './PatchOperation' -import { LoginRequestSchema } from './identity/login/LoginRequest' -import { PagedRequestSchema } from './PagedRequest' -import { PatchRequestModelBaseSchema } from './PatchRequestModelBase' -import { RefreshTokenRequestSchema } from './identity/login/RefreshTokenRequest' +import { PatchOperation } from '../src/PatchOperation' +import { LoginRequestSchema } from '../src/identity/login/LoginRequest' +import { PagedRequestSchema } from '../src/PagedRequest' +import { PatchRequestModelBaseSchema } from '../src/PatchRequestModelBase' +import { RefreshTokenRequestSchema } from '../src/identity/login/RefreshTokenRequest' describe('LoginRequestSchema', () => { it('accepts valid credentials', () => { diff --git a/src/packages/contracts/tsconfig.json b/src/packages/contracts/tsconfig.json index 90d6d34..5285d28 100644 --- a/src/packages/contracts/tsconfig.json +++ b/src/packages/contracts/tsconfig.json @@ -4,6 +4,5 @@ "rootDir": "src", "outDir": "dist" }, - "include": ["src"], - "exclude": ["src/**/*.test.ts"] + "include": ["src"] } diff --git a/src/packages/core/README.md b/src/packages/core/README.md index fb83459..031d0e9 100644 --- a/src/packages/core/README.md +++ b/src/packages/core/README.md @@ -7,7 +7,7 @@ Depends on `@maks-it.com/webui-contracts`. Install peer dependencies in the host ## Install ```bash -npm install @maks-it.com/webui-core @maks-it.com/webui-contracts axios react zod +npm install @maks-it.com/webui-core @maks-it.com/webui-contracts @microsoft/signalr axios react zod ``` ## Highlights @@ -20,6 +20,7 @@ npm install @maks-it.com/webui-core @maks-it.com/webui-contracts axios react zod | DataTable | `mapPagedToDataTable`, `extractPropFilter`, `DataTablePageView` | | ACL | `parseAclEntry`, `parseAclEntries` | | HTTP | `createWebUiHttpClient`, auth interceptors, Problem Details helpers | +| SignalR | `useWebUiHub` | | Enum / flags | `enumToArr`, `flagsToString`, `hasFlag`, `toggleFlag` | | Identity storage | `readIdentity`, `writeIdentity`, `removeIdentity` | @@ -40,6 +41,25 @@ function MyForm() { } ``` +## Example — SignalR hub + +```tsx +import { readIdentity, useWebUiHub } from '@maks-it.com/webui-core' + +function JobProgressPanel({ canSubscribe }: { canSubscribe: boolean }) { + const [progress, setProgress] = useState() + + const { connectionState } = useWebUiHub({ + hubUrl: '/hubs/jobs', + enabled: canSubscribe, + accessToken: () => readIdentity()?.token, + events: { progressUpdated: setProgress }, + }) + + // connectionState: idle | connecting | connected | reconnecting | disconnected +} +``` + ## Example — PATCH delta ```ts diff --git a/src/packages/core/package.json b/src/packages/core/package.json index 0c51c83..7501842 100644 --- a/src/packages/core/package.json +++ b/src/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@maks-it.com/webui-core", - "version": "0.3.2", + "version": "0.3.3", "description": "Shared utilities and hooks for MaksIT WebUI apps", "type": "module", "main": "./dist/index.cjs", @@ -34,15 +34,17 @@ "directory": "src/packages/core" }, "dependencies": { - "@maks-it.com/webui-contracts": "^0.3.2", + "@maks-it.com/webui-contracts": "^0.3.3", "date-fns": "^4.3.0" }, "peerDependencies": { + "@microsoft/signalr": "^8.0.0", "axios": "^1.16.0", "react": "^18.0.0 || ^19.0.0", "zod": "^4.4.0" }, "devDependencies": { + "@microsoft/signalr": "^8.0.7", "@types/react": "^19.2.15", "axios": "^1.16.1", "react": "^19.2.6", diff --git a/src/packages/core/src/index.ts b/src/packages/core/src/index.ts index 6a12670..d64cd59 100644 --- a/src/packages/core/src/index.ts +++ b/src/packages/core/src/index.ts @@ -1,5 +1,6 @@ export * from './functions' export * from './types' export * from './http' +export * from './signalr' export { readIdentity, writeIdentity, removeIdentity } from './localStorage/identity' export { useFormState } from './hooks/useFormState' diff --git a/src/packages/core/src/signalr/index.ts b/src/packages/core/src/signalr/index.ts new file mode 100644 index 0000000..b864c57 --- /dev/null +++ b/src/packages/core/src/signalr/index.ts @@ -0,0 +1,7 @@ +export { useWebUiHub } from './useWebUiHub' +export type { + UseWebUiHubOptions, + UseWebUiHubResult, + WebUiHubAccessTokenFactory, + WebUiHubConnectionState, +} from './useWebUiHub' diff --git a/src/packages/core/src/signalr/useWebUiHub.ts b/src/packages/core/src/signalr/useWebUiHub.ts new file mode 100644 index 0000000..6f76bc4 --- /dev/null +++ b/src/packages/core/src/signalr/useWebUiHub.ts @@ -0,0 +1,139 @@ +import { HubConnectionBuilder, HubConnectionState } from '@microsoft/signalr' +import { useEffect, useRef, useState } from 'react' + +export type WebUiHubConnectionState = + | 'idle' + | 'connecting' + | 'connected' + | 'reconnecting' + | 'disconnected' + +export type WebUiHubAccessTokenFactory = () => string | undefined | Promise + +export interface UseWebUiHubOptions { + /** Absolute URL or path (e.g. `/hubs/my-hub`). Paths resolve against `window.location.origin`. */ + hubUrl: string + /** When false, no connection is opened. Default: true. */ + enabled?: boolean + accessToken: WebUiHubAccessTokenFactory + /** Hub method name -> handler. */ + events: Record void> + automaticReconnect?: boolean +} + +export interface UseWebUiHubResult { + connectionState: WebUiHubConnectionState + lastError: unknown +} + +export const resolveHubUrl = (hubUrl: string): string => { + if (/^https?:\/\//i.test(hubUrl)) + return hubUrl + + const base = typeof globalThis !== 'undefined' && 'location' in globalThis + ? globalThis.location.origin + : '' + + const path = hubUrl.startsWith('/') ? hubUrl : `/${hubUrl}` + return `${base}${path}` +} + +const eventKeys = (events: Record): string => + Object.keys(events).sort().join('\0') + +/** JWT-authenticated SignalR hub with reconnect handling. */ +export const useWebUiHub = (options: UseWebUiHubOptions): UseWebUiHubResult => { + const { + hubUrl, + enabled = true, + accessToken, + events, + automaticReconnect, + } = options + + const accessTokenRef = useRef(accessToken) + accessTokenRef.current = accessToken + + const eventsRef = useRef(events) + eventsRef.current = events + + const [connectionState, setConnectionState] = useState( + enabled ? 'connecting' : 'idle' + ) + const [lastError, setLastError] = useState(undefined) + + const subscribedEvents = eventKeys(events) + + useEffect(() => { + if (!enabled) { + setConnectionState('idle') + setLastError(undefined) + return + } + + let disposed = false + const wrappers = new Map void>() + + const builder = new HubConnectionBuilder() + .withUrl(resolveHubUrl(hubUrl), { + accessTokenFactory: async () => (await accessTokenRef.current()) ?? '', + }) + + if (automaticReconnect !== false) + builder.withAutomaticReconnect() + + const connection = builder.build() + + for (const eventName of Object.keys(eventsRef.current)) { + const wrapper = (payload: unknown) => eventsRef.current[eventName]?.(payload) + wrappers.set(eventName, wrapper) + connection.on(eventName, wrapper) + } + + connection.onreconnecting(() => { + if (!disposed) + setConnectionState('reconnecting') + }) + + connection.onreconnected(() => { + if (!disposed) + setConnectionState('connected') + }) + + connection.onclose(error => { + if (!disposed) { + setConnectionState('disconnected') + if (error) + setLastError(error) + } + }) + + setConnectionState('connecting') + setLastError(undefined) + + void connection.start() + .then(() => { + if (!disposed) + setConnectionState('connected') + }) + .catch(error => { + if (!disposed) { + setConnectionState('disconnected') + setLastError(error) + } + }) + + return () => { + disposed = true + for (const [eventName, wrapper] of wrappers) + connection.off(eventName, wrapper) + + if (connection.state === HubConnectionState.Connected + || connection.state === HubConnectionState.Reconnecting) { + void connection.stop() + } + } + }, [enabled, hubUrl, subscribedEvents, automaticReconnect]) + + return { connectionState, lastError } +} diff --git a/src/packages/core/src/functions/acl/parseAclEntry.test.ts b/src/packages/core/test/functions/acl/parseAclEntry.test.ts similarity index 85% rename from src/packages/core/src/functions/acl/parseAclEntry.test.ts rename to src/packages/core/test/functions/acl/parseAclEntry.test.ts index 475e4a8..2a2bffd 100644 --- a/src/packages/core/src/functions/acl/parseAclEntry.test.ts +++ b/src/packages/core/test/functions/acl/parseAclEntry.test.ts @@ -1,5 +1,5 @@ -import { ScopePermission } from '../../types/ScopePermissions' -import { parseAclEntry, parseAclEntries } from './parseAclEntry' +import { ScopePermission } from '../../../src/types/ScopePermissions' +import { parseAclEntry, parseAclEntries } from '../../../src/functions/acl/parseAclEntry' const entityTypeMap = { O: 1, V: 2 } as const diff --git a/src/packages/core/src/functions/dataTable/dataTableFilters.test.ts b/src/packages/core/test/functions/dataTable/dataTableFilters.test.ts similarity index 91% rename from src/packages/core/src/functions/dataTable/dataTableFilters.test.ts rename to src/packages/core/test/functions/dataTable/dataTableFilters.test.ts index ec03d09..10d3406 100644 --- a/src/packages/core/src/functions/dataTable/dataTableFilters.test.ts +++ b/src/packages/core/test/functions/dataTable/dataTableFilters.test.ts @@ -1,4 +1,4 @@ -import { extractPropFilter } from './dataTableFilters' +import { extractPropFilter } from '../../../src/functions/dataTable/dataTableFilters' describe('extractPropFilter', () => { it('extracts Contains filter values', () => { diff --git a/src/packages/core/src/functions/dataTable/dataTablePaged.test.ts b/src/packages/core/test/functions/dataTable/dataTablePaged.test.ts similarity index 93% rename from src/packages/core/src/functions/dataTable/dataTablePaged.test.ts rename to src/packages/core/test/functions/dataTable/dataTablePaged.test.ts index 22773a8..07bcef1 100644 --- a/src/packages/core/src/functions/dataTable/dataTablePaged.test.ts +++ b/src/packages/core/test/functions/dataTable/dataTablePaged.test.ts @@ -1,5 +1,5 @@ import type { PagedResponse } from '@maks-it.com/webui-contracts' -import { mapPagedToDataTable } from './dataTablePaged' +import { mapPagedToDataTable } from '../../../src/functions/dataTable/dataTablePaged' describe('mapPagedToDataTable', () => { it('returns an empty page for missing responses', () => { diff --git a/src/packages/core/src/functions/date/isValidDateString.test.ts b/src/packages/core/test/functions/date/isValidDateString.test.ts similarity index 83% rename from src/packages/core/src/functions/date/isValidDateString.test.ts rename to src/packages/core/test/functions/date/isValidDateString.test.ts index adc88e9..85a0d18 100644 --- a/src/packages/core/src/functions/date/isValidDateString.test.ts +++ b/src/packages/core/test/functions/date/isValidDateString.test.ts @@ -1,4 +1,4 @@ -import { isValidISODateString } from './isValidDateString' +import { isValidISODateString } from '../../../src/functions/date/isValidDateString' describe('isValidISODateString', () => { it('accepts valid ISO date strings', () => { diff --git a/src/packages/core/src/functions/deep/deepDelta.test.ts b/src/packages/core/test/functions/deep/deepDelta.test.ts similarity index 97% rename from src/packages/core/src/functions/deep/deepDelta.test.ts rename to src/packages/core/test/functions/deep/deepDelta.test.ts index 3526e7c..577a528 100644 --- a/src/packages/core/src/functions/deep/deepDelta.test.ts +++ b/src/packages/core/test/functions/deep/deepDelta.test.ts @@ -1,5 +1,5 @@ import { COLLECTION_ITEM_OPERATION, PatchOperation } from '@maks-it.com/webui-contracts' -import { deepDelta, deltaHasOperations } from './deepDelta' +import { deepDelta, deltaHasOperations } from '../../../src/functions/deep/deepDelta' describe('deepDelta', () => { it('detects primitive field changes', () => { diff --git a/src/packages/core/src/functions/deep/deepEqual.test.ts b/src/packages/core/test/functions/deep/deepEqual.test.ts similarity index 93% rename from src/packages/core/src/functions/deep/deepEqual.test.ts rename to src/packages/core/test/functions/deep/deepEqual.test.ts index b5f2845..e911ab5 100644 --- a/src/packages/core/src/functions/deep/deepEqual.test.ts +++ b/src/packages/core/test/functions/deep/deepEqual.test.ts @@ -1,4 +1,4 @@ -import { deepEqual, deepEqualArrays } from './deepEqual' +import { deepEqual, deepEqualArrays } from '../../../src/functions/deep/deepEqual' describe('deepEqual', () => { it('returns true for identical primitives', () => { diff --git a/src/packages/core/src/functions/enum/flags.test.ts b/src/packages/core/test/functions/enum/flags.test.ts similarity index 79% rename from src/packages/core/src/functions/enum/flags.test.ts rename to src/packages/core/test/functions/enum/flags.test.ts index d64f147..fb69479 100644 --- a/src/packages/core/src/functions/enum/flags.test.ts +++ b/src/packages/core/test/functions/enum/flags.test.ts @@ -1,6 +1,6 @@ -import { hasAnyFlag } from './hasAnyFlag' -import { hasFlag } from './hasFlag' -import { toggleFlag } from './toggleFlag' +import { hasAnyFlag } from '../../../src/functions/enum/hasAnyFlag' +import { hasFlag } from '../../../src/functions/enum/hasFlag' +import { toggleFlag } from '../../../src/functions/enum/toggleFlag' describe('hasFlag', () => { it('returns true when all flag bits are set', () => { diff --git a/src/packages/core/src/functions/guid/isGuid.test.ts b/src/packages/core/test/functions/guid/isGuid.test.ts similarity index 88% rename from src/packages/core/src/functions/guid/isGuid.test.ts rename to src/packages/core/test/functions/guid/isGuid.test.ts index 812464c..89be5e4 100644 --- a/src/packages/core/src/functions/guid/isGuid.test.ts +++ b/src/packages/core/test/functions/guid/isGuid.test.ts @@ -1,4 +1,4 @@ -import { isGuid } from './isGuid' +import { isGuid } from '../../../src/functions/guid/isGuid' describe('isGuid', () => { it('accepts valid GUIDs', () => { diff --git a/src/packages/core/src/functions/headers/extractFilenameFromHeaders.test.ts b/src/packages/core/test/functions/headers/extractFilenameFromHeaders.test.ts similarity index 88% rename from src/packages/core/src/functions/headers/extractFilenameFromHeaders.test.ts rename to src/packages/core/test/functions/headers/extractFilenameFromHeaders.test.ts index 3b2def5..16f6ea3 100644 --- a/src/packages/core/src/functions/headers/extractFilenameFromHeaders.test.ts +++ b/src/packages/core/test/functions/headers/extractFilenameFromHeaders.test.ts @@ -1,4 +1,4 @@ -import { extractFilenameFromHeaders } from './extractFilenameFromHeaders' +import { extractFilenameFromHeaders } from '../../../src/functions/headers/extractFilenameFromHeaders' describe('extractFilenameFromHeaders', () => { it('returns fallback when header is missing', () => { diff --git a/src/packages/core/src/functions/zod/validateFormState.test.ts b/src/packages/core/test/functions/zod/validateFormState.test.ts similarity index 89% rename from src/packages/core/src/functions/zod/validateFormState.test.ts rename to src/packages/core/test/functions/zod/validateFormState.test.ts index 2eb8e71..b9b6246 100644 --- a/src/packages/core/src/functions/zod/validateFormState.test.ts +++ b/src/packages/core/test/functions/zod/validateFormState.test.ts @@ -1,5 +1,5 @@ import { z } from 'zod' -import { validateFormState } from './validateFormState' +import { validateFormState } from '../../../src/functions/zod/validateFormState' describe('validateFormState', () => { const schema = z.object({ diff --git a/src/packages/core/src/http/problemDetails.test.ts b/src/packages/core/test/http/problemDetails.test.ts similarity index 91% rename from src/packages/core/src/http/problemDetails.test.ts rename to src/packages/core/test/http/problemDetails.test.ts index e97ccbb..f4ce91b 100644 --- a/src/packages/core/src/http/problemDetails.test.ts +++ b/src/packages/core/test/http/problemDetails.test.ts @@ -1,4 +1,4 @@ -import { formatProblemDetailsMessage } from './problemDetails' +import { formatProblemDetailsMessage } from '../../src/http/problemDetails' describe('formatProblemDetailsMessage', () => { it('combines detail and field errors', () => { diff --git a/src/packages/core/test/signalr/useWebUiHub.test.ts b/src/packages/core/test/signalr/useWebUiHub.test.ts new file mode 100644 index 0000000..d0ea444 --- /dev/null +++ b/src/packages/core/test/signalr/useWebUiHub.test.ts @@ -0,0 +1,31 @@ +import { resolveHubUrl, useWebUiHub } from '../../src/signalr/useWebUiHub' + +describe('resolveHubUrl', () => { + it('returns absolute URLs unchanged', () => { + expect(resolveHubUrl('https://api.example/hubs/jobs')).toBe('https://api.example/hubs/jobs') + }) + + it('prefixes relative paths with origin', () => { + Object.defineProperty(globalThis, 'location', { + configurable: true, + value: { origin: 'http://localhost:8080' }, + }) + + expect(resolveHubUrl('/hubs/key-migration')).toBe('http://localhost:8080/hubs/key-migration') + }) + + it('adds leading slash when missing', () => { + Object.defineProperty(globalThis, 'location', { + configurable: true, + value: { origin: 'http://localhost:8080' }, + }) + + expect(resolveHubUrl('hubs/events')).toBe('http://localhost:8080/hubs/events') + }) +}) + +describe('useWebUiHub', () => { + it('exports the hook', () => { + expect(typeof useWebUiHub).toBe('function') + }) +}) diff --git a/src/packages/core/tsconfig.json b/src/packages/core/tsconfig.json index 90d6d34..5285d28 100644 --- a/src/packages/core/tsconfig.json +++ b/src/packages/core/tsconfig.json @@ -4,6 +4,5 @@ "rootDir": "src", "outDir": "dist" }, - "include": ["src"], - "exclude": ["src/**/*.test.ts"] + "include": ["src"] } diff --git a/src/tsconfig.jest.json b/src/tsconfig.jest.json index 64e8225..cf5da01 100644 --- a/src/tsconfig.jest.json +++ b/src/tsconfig.jest.json @@ -6,6 +6,8 @@ }, "include": [ "packages/core/src/**/*.ts", - "packages/contracts/src/**/*.ts" + "packages/core/test/**/*.ts", + "packages/contracts/src/**/*.ts", + "packages/contracts/test/**/*.ts" ] } diff --git a/utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.bat b/utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.bat deleted file mode 100644 index 20029f8..0000000 --- a/utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -pwsh -NoProfile -ExecutionPolicy Bypass -File "%~dp0Force-AmendTaggedCommit.ps1" -pause diff --git a/utils/Generate-CoverageBadges/Generate-CoverageBadges.bat b/utils/Generate-CoverageBadges/Generate-CoverageBadges.bat deleted file mode 100644 index 2790074..0000000 --- a/utils/Generate-CoverageBadges/Generate-CoverageBadges.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -pwsh -NoProfile -ExecutionPolicy Bypass -File "%~dp0Generate-CoverageBadges.ps1" -pause diff --git a/utils/Generate-CoverageBadges/Generate-CoverageBadges.ps1 b/utils/Generate-CoverageBadges/Generate-CoverageBadges.ps1 deleted file mode 100644 index dff68c1..0000000 --- a/utils/Generate-CoverageBadges/Generate-CoverageBadges.ps1 +++ /dev/null @@ -1,22 +0,0 @@ -#requires -Version 7.0 -#requires -PSEdition Core - -<# -.SYNOPSIS - Legacy entry point — forwards to the Run-Tests plugin engine. - -.DESCRIPTION - Generate-CoverageBadges.ps1 is kept for backward compatibility. - Configure plugins in src/Run-Tests/scriptsettings.json. -#> - -$ErrorActionPreference = "Stop" - -$runTestsScript = Join-Path (Split-Path $PSScriptRoot -Parent) "Run-Tests\Run-Tests.ps1" -if (-not (Test-Path $runTestsScript -PathType Leaf)) { - Write-Error "Run-Tests engine not found at: $runTestsScript" - exit 1 -} - -& pwsh -NoProfile -ExecutionPolicy Bypass -File $runTestsScript -exit $LASTEXITCODE diff --git a/utils/Generate-CoverageBadges/scriptsettings.json b/utils/Generate-CoverageBadges/scriptsettings.json deleted file mode 100644 index a3169f5..0000000 --- a/utils/Generate-CoverageBadges/scriptsettings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft-07/schema", - "title": "Generate Coverage Badges Script Settings", - "description": "Legacy settings file. Use utils/Run-Tests/scriptsettings.json instead.", - "_forwardTo": "..\\Run-Tests\\scriptsettings.json" -} diff --git a/utils/Release-Package/PluginSupport.psm1 b/utils/Release-Package/PluginSupport.psm1 deleted file mode 100644 index b86e733..0000000 --- a/utils/Release-Package/PluginSupport.psm1 +++ /dev/null @@ -1,379 +0,0 @@ -#requires -Version 7.0 -#requires -PSEdition Core - -if (-not (Get-Command Write-Log -ErrorAction SilentlyContinue)) { - $loggingModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "Logging.psm1" - if (Test-Path $loggingModulePath -PathType Leaf) { - Import-Module $loggingModulePath -Force - } -} - -function Import-PluginDependency { - param( - [Parameter(Mandatory = $true)] - [string]$ModuleName, - - [Parameter(Mandatory = $true)] - [string]$RequiredCommand - ) - - if (Get-Command $RequiredCommand -ErrorAction SilentlyContinue) { - return - } - - $moduleRoot = Split-Path $PSScriptRoot -Parent - $modulePath = Join-Path $moduleRoot "$ModuleName.psm1" - if (Test-Path $modulePath -PathType Leaf) { - # Import into the global session so the calling plugin can see the exported commands. - # Importing only into this module's scope would make the dependency invisible to the plugin. - Import-Module $modulePath -Force -Global -ErrorAction Stop - } - - if (-not (Get-Command $RequiredCommand -ErrorAction SilentlyContinue)) { - throw "Required command '$RequiredCommand' is still unavailable after importing module '$ModuleName'." - } -} - -function Get-ConfiguredPlugins { - param( - [Parameter(Mandatory = $true)] - [psobject]$Settings - ) - - if (-not $Settings.PSObject.Properties['plugins'] -or $null -eq $Settings.plugins) { - return @() - } - - # JSON can deserialize a single plugin as one object or multiple plugins as an array. - # Always return an array so the engine can loop without special-case logic. - if ($Settings.plugins -is [System.Collections.IEnumerable] -and -not ($Settings.plugins -is [string])) { - return @($Settings.plugins) - } - - return @($Settings.plugins) -} - -function Get-PluginStageLabel { - param( - [Parameter(Mandatory = $true)] - $Plugin - ) - - if (-not $Plugin.PSObject.Properties['stageLabel'] -or [string]::IsNullOrWhiteSpace([string]$Plugin.stageLabel)) { - return 'release' - } - - return [string]$Plugin.stageLabel -} - -function Get-PluginBranches { - param( - [Parameter(Mandatory = $true)] - $Plugin - ) - - if (-not $Plugin.PSObject.Properties['branches'] -or $null -eq $Plugin.branches) { - return @() - } - - # Strings are also IEnumerable in PowerShell, so exclude them or we would split into characters. - if ($Plugin.branches -is [System.Collections.IEnumerable] -and -not ($Plugin.branches -is [string])) { - return @($Plugin.branches | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) - } - - if ([string]::IsNullOrWhiteSpace([string]$Plugin.branches)) { - return @() - } - - return @([string]$Plugin.branches) -} - -function Test-PluginAllowedOnBranch { - param( - [Parameter(Mandatory = $true)] - $Plugin, - - [Parameter(Mandatory = $true)] - [string]$CurrentBranch - ) - - $allowedBranches = Get-PluginBranches -Plugin $Plugin - if ($allowedBranches.Count -eq 0) { - return $true - } - - if ($allowedBranches -contains '*') { - return $true - } - - return $allowedBranches -contains $CurrentBranch -} - -function Test-IsPublishPlugin { - param( - [Parameter(Mandatory = $true)] - $Plugin - ) - - if ($null -eq $Plugin -or [string]::IsNullOrWhiteSpace([string]$Plugin.name)) { - return $false - } - - return @('GitHub', 'DotNetNuGet', 'DockerPush', 'HelmPush', 'NpmPublish') -contains ([string]$Plugin.name) -} - -function Get-PluginSettingValue { - param( - [Parameter(Mandatory = $true)] - [object[]]$Plugins, - - [Parameter(Mandatory = $true)] - [string]$PropertyName - ) - - foreach ($plugin in $Plugins) { - if ($null -eq $plugin -or [string]::IsNullOrWhiteSpace($plugin.name)) { - continue - } - - if (-not $plugin.PSObject.Properties[$PropertyName]) { - continue - } - - $value = $plugin.$PropertyName - if ($null -eq $value) { - continue - } - - if ($value -is [string] -and [string]::IsNullOrWhiteSpace($value)) { - continue - } - - return $value - } - - return $null -} - -function Get-PluginPathListSetting { - param( - [Parameter(Mandatory = $true)] - [object[]]$Plugins, - - [Parameter(Mandatory = $true)] - [string]$PropertyName, - - [Parameter(Mandatory = $true)] - [string]$BasePath - ) - - $rawPaths = @() - $value = Get-PluginSettingValue -Plugins $Plugins -PropertyName $PropertyName - - if ($null -eq $value) { - return @() - } - - # Same rule as above: treat a string as one path, not a char-by-char sequence. - if ($value -is [System.Collections.IEnumerable] -and -not ($value -is [string])) { - $rawPaths += $value - } - else { - $rawPaths += $value - } - - $resolvedPaths = @() - foreach ($path in $rawPaths) { - if ([string]::IsNullOrWhiteSpace([string]$path)) { - continue - } - - $resolvedPaths += [System.IO.Path]::GetFullPath((Join-Path $BasePath ([string]$path))) - } - - # Wrap again to stop PowerShell from unrolling a single-item array into a bare string. - return @($resolvedPaths) -} - -function Get-PluginPathSetting { - param( - [Parameter(Mandatory = $true)] - [object[]]$Plugins, - - [Parameter(Mandatory = $true)] - [string]$PropertyName, - - [Parameter(Mandatory = $true)] - [string]$BasePath - ) - - $value = Get-PluginSettingValue -Plugins $Plugins -PropertyName $PropertyName - if ($null -eq $value -or [string]::IsNullOrWhiteSpace([string]$value)) { - return $null - } - - return [System.IO.Path]::GetFullPath((Join-Path $BasePath ([string]$value))) -} - -function Get-ArchiveNamePattern { - param( - [Parameter(Mandatory = $true)] - [object[]]$Plugins, - - [Parameter(Mandatory = $true)] - [string]$CurrentBranch - ) - - foreach ($plugin in $Plugins) { - if ($null -eq $plugin -or [string]::IsNullOrWhiteSpace($plugin.name)) { - continue - } - - if (-not $plugin.enabled) { - continue - } - - if (-not (Test-PluginAllowedOnBranch -Plugin $plugin -CurrentBranch $CurrentBranch)) { - continue - } - - if ($plugin.PSObject.Properties['zipNamePattern'] -and -not [string]::IsNullOrWhiteSpace([string]$plugin.zipNamePattern)) { - return [string]$plugin.zipNamePattern - } - } - - return "release-{version}.zip" -} - -function Resolve-PluginModulePath { - param( - [Parameter(Mandatory = $true)] - $Plugin, - - [Parameter(Mandatory = $true)] - [string]$PluginsDirectory - ) - - $pluginFileName = "{0}.psm1" -f $Plugin.name - $candidatePaths = @( - (Join-Path $PluginsDirectory $pluginFileName), - (Join-Path (Join-Path (Split-Path $PluginsDirectory -Parent) "CustomPlugins") $pluginFileName) - ) - - foreach ($candidatePath in $candidatePaths) { - if (Test-Path $candidatePath -PathType Leaf) { - return $candidatePath - } - } - - return $candidatePaths[0] -} - -function Test-PluginRunnable { - param( - [Parameter(Mandatory = $true)] - $Plugin, - - [Parameter(Mandatory = $true)] - [psobject]$SharedSettings, - - [Parameter(Mandatory = $true)] - [string]$PluginsDirectory, - - [Parameter(Mandatory = $false)] - [bool]$WriteLogs = $true - ) - - if ($null -eq $Plugin -or [string]::IsNullOrWhiteSpace($Plugin.name)) { - if ($WriteLogs) { - Write-Log -Level "WARN" -Message "Skipping plugin entry with no name." - } - return $false - } - - if (-not $Plugin.enabled) { - if ($WriteLogs) { - Write-Log -Level "WARN" -Message "Skipping plugin '$($Plugin.name)' (disabled)." - } - return $false - } - - $pluginModulePath = Resolve-PluginModulePath -Plugin $Plugin -PluginsDirectory $PluginsDirectory - if (-not (Test-Path $pluginModulePath -PathType Leaf)) { - if ($WriteLogs) { - Write-Log -Level "ERROR" -Message "Plugin module not found: $pluginModulePath" - } - return $false - } - - return $true -} - -function New-PluginInvocationSettings { - param( - [Parameter(Mandatory = $true)] - $Plugin, - - [Parameter(Mandatory = $true)] - [psobject]$SharedSettings - ) - - $properties = @{} - foreach ($property in $Plugin.PSObject.Properties) { - $properties[$property.Name] = $property.Value - } - - # Plugins receive their own config plus shared runtime context. - $properties['context'] = $SharedSettings - return [pscustomobject]$properties -} - -function Invoke-ConfiguredPlugin { - param( - [Parameter(Mandatory = $true)] - $Plugin, - - [Parameter(Mandatory = $true)] - [psobject]$SharedSettings, - - [Parameter(Mandatory = $true)] - [string]$PluginsDirectory, - - [Parameter(Mandatory = $false)] - [bool]$ContinueOnError = $false - ) - - if (-not (Test-PluginRunnable -Plugin $Plugin -SharedSettings $SharedSettings -PluginsDirectory $PluginsDirectory -WriteLogs:$true)) { - if ($Plugin.enabled) { - return $false - } - - return $true - } - - if ((Test-IsPublishPlugin -Plugin $Plugin) -and ($SharedSettings.PSObject.Properties.Name -contains 'skipPublishPlugins') -and $SharedSettings.skipPublishPlugins) { - Write-Log -Level "INFO" -Message "Skipping plugin '$($Plugin.name)' (ReleasePublishGuard suppressed publish)." - return $true - } - - $pluginModulePath = Resolve-PluginModulePath -Plugin $Plugin -PluginsDirectory $PluginsDirectory - Write-Log -Level "STEP" -Message "Running plugin '$($Plugin.name)'..." - - try { - $moduleInfo = Import-Module $pluginModulePath -Force -PassThru -ErrorAction Stop - # Resolve Invoke-Plugin from the imported module explicitly so we call the plugin we just loaded, - # not some command with the same name from another module already in session. - $invokeCommand = Get-Command -Name "Invoke-Plugin" -Module $moduleInfo.Name -ErrorAction Stop - $pluginSettings = New-PluginInvocationSettings -Plugin $Plugin -SharedSettings $SharedSettings - - & $invokeCommand -Settings $pluginSettings - Write-Log -Level "OK" -Message " Plugin '$($Plugin.name)' completed." - return $true - } - catch { - Write-Log -Level "ERROR" -Message " Plugin '$($Plugin.name)' failed: $($_.Exception.Message)" - return $false - } -} - -Export-ModuleMember -Function Import-PluginDependency, Get-ConfiguredPlugins, Get-PluginStageLabel, Get-PluginBranches, Test-IsPublishPlugin, Get-PluginSettingValue, Get-PluginPathListSetting, Get-PluginPathSetting, Get-ArchiveNamePattern, Resolve-PluginModulePath, Test-PluginRunnable, New-PluginInvocationSettings, Invoke-ConfiguredPlugin diff --git a/utils/Release-Package/README.md b/utils/Release-Package/README.md deleted file mode 100644 index 851b76f..0000000 --- a/utils/Release-Package/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# Release-Package - -Plugin-driven release engine. Run `Release-Package.ps1` from this directory (or `Release-Package.bat`). Configuration: `scriptsettings.json` (see `_comments` for plugin keys). - -Canonical source: this folder in **maksit-repoutils**. Product repositories refresh via `Update-RepoUtils` or by copying from here. - -## Modules (orchestration) - -| File | Role | -|------|------| -| `Release-Package.ps1` | Loads settings, builds `New-EngineContext`, runs plugins in order. | -| `PluginSupport.psm1` | Plugin discovery, `Invoke-ConfiguredPlugin`; publish plugins honor `skipPublishPlugins` from `ReleasePublishGuard` (no per-plugin `branches` for GitHub/NuGet/Docker/Helm). | -| `ReleaseContext.psm1` | Resolves semver via `Resolve-ReleaseVersion` from `DotNetReleaseVersion.projectFiles` (first `.csproj` ``) or `NpmReleaseVersion.packageJsonPath`. | -| `EngineSupport.psm1` | Warn-only dirty-tree preflight; default `context.tag` = `v{version}` from the configured version plugin; `Initialize-ReleaseStageContext` sets `releaseDir` only. | - -Shared module `../ChangelogSupport.psm1` (repo `src/`) parses release notes for the GitHub plugin: only `## [semver] - YYYY-MM-DD` version lines (Keep a Changelog). The latest header must match `context.version` from the version plugin. - -## Plugins - -`CorePlugins/` — e.g. `DotNetReleaseVersion`, `NpmReleaseVersion`, `NpmBuild`, `NpmPublish`, `DockerPush`, `HelmPush`, `ReleasePublishGuard`. Optional `CustomPlugins/`. - -`DotNetPack` and `QualityGate` (when used) can declare their own `projectFiles`; semver still comes from the configured version plugin (`DotNetReleaseVersion` or `NpmReleaseVersion`). - -## `ReleasePublishGuard` - -Configure this plugin **immediately before** `DockerPush`, `HelmPush`, `GitHub`, `DotNetNuGet`, and `NpmPublish`. It sets shared `skipPublishPlugins` when branch/tag rules fail (`whenRequirementsNotMet`: `skip` or `fail`). Those publish plugins no longer use their own `branches` key — list allowed branches on the guard only. Preflight does not read git tags; the guard sets `context.tag` from `HEAD` when `requireExactTagOnHead` is true. **`context.version` stays from the version plugin** (`DotNetReleaseVersion` or `NpmReleaseVersion`; the guard does not override it). Use `tagVersionMustMatchReleaseVersion` (or legacy `tagVersionMustMatchDotNetRelease` / `tagVersionMustMatchNpmRelease`) to require the git tag semver to match `context.version`. - -## npm workspaces - -For TypeScript monorepos published to npmjs: - -1. `NpmReleaseVersion` — reads `packageJsonPath` (workspace root `package.json`), optional `syncWorkspaceVersions: true` to align `packages/*/package.json` versions. -2. `NpmBuild` — `npm ci` + `npm run build` in `workspaceRoot` (defaults to shared `npmWorkspaceRoot` from step 1). -3. `ReleasePublishGuard` — same tag/branch rules; set `tagVersionMustMatchReleaseVersion: true`. -4. `NpmPublish` — `publishOrder` workspace package names, `npmApiKey` env var name (e.g. `NPMJS_MAKS_IT`), optional `registry` / `access`. - -## `DotNetTest` and shared context - -`DotNetTest` runs once and writes aggregated coverage and test metrics on the shared engine context (`qualityLineCoverage`, `coverageLineRate`, `testResult`, …). `QualityGate` reads those values for optional line-coverage thresholds; it does not re-run tests. Set `scanVulnerabilities` to false to skip `dotnet list package --vulnerable`. - -## Helm charts in git - -Commit `Chart.yaml` with placeholder `version` and `appVersion` (for example `0.0.0`) so `helm lint` stays valid. `HelmPush` temporarily replaces both with the **bare** release semver from `context.version` (`DotNetReleaseVersion`, e.g. `3.3.4` without a `v` prefix) before packaging and OCI push; if `version` were missing, it would fall back to stripping `v`/`V` from `context.tag`. Then it restores `Chart.yaml`. `DockerPush` tags images with the **bare** semver from `context.version` (e.g. `3.3.4`), also pushes `vX.Y.Z` and `shared.tag` when they differ, and optional `latest` — not from `Chart.yaml`; optionally use per-image `versionEnvFiles` to temporarily set `VITE_APP_VERSION={shared.version}` in frontend `.env` files during docker build, then restore originals. Each image may override the plugin `contextPath` with its own `contextPath` (paths relative to Release-Package); `dockerfile` and `versionEnvFiles` resolve against that per-image context. - -Sample chart: repository `charts/my-service/` (matches the sample `chartPath` in `scriptsettings.json`). Product repos often use `src/helm/` instead. - diff --git a/utils/Release-Package/Release-Package.bat b/utils/Release-Package/Release-Package.bat deleted file mode 100644 index 6a4aba8..0000000 --- a/utils/Release-Package/Release-Package.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -pwsh -NoProfile -ExecutionPolicy Bypass -File "%~dp0Release-Package.ps1" -pause diff --git a/utils/Release-Package/Release-Package.ps1 b/utils/Release-Package/Release-Package.ps1 deleted file mode 100644 index 18ef7db..0000000 --- a/utils/Release-Package/Release-Package.ps1 +++ /dev/null @@ -1,199 +0,0 @@ -#requires -Version 7.0 -#requires -PSEdition Core - -<# -.SYNOPSIS - Plugin-driven release engine. - -.DESCRIPTION - This script is the orchestration layer for release automation. - It loads scriptsettings.json, evaluates the configured plugins in order, - builds shared execution context, and invokes each plugin's Invoke-Plugin - entrypoint with that plugin's own settings object plus runtime context. - - The engine is intentionally generic: - - It does not embed release-provider-specific logic - - It preserves plugin execution order from scriptsettings.json - - It isolates plugin failures according to the stage/runtime policy - - It keeps shared orchestration helpers in dedicated support modules - -.REQUIREMENTS - Tools (Required): - - Shared support modules required by the engine - - Any commands required by configured plugins or support helpers - -.WORKFLOW - 1. Load and normalize plugin configuration - 2. Determine branch mode from configured plugin metadata - 3. Validate repository state and resolve the release version - 4. Build shared execution context - 5. Execute plugins one by one in configured order - 6. Initialize release-stage shared artifacts only when needed - 7. Report completion summary - -.USAGE - Configure plugin order and plugin settings in scriptsettings.json, then run: - pwsh -File .\Release-Package.ps1 - -.CONFIGURATION - All settings are stored in scriptsettings.json: - - plugins: Ordered plugin definitions and plugin-specific settings - -.NOTES - Plugin-specific behavior belongs in the plugin modules, not in this engine. -#> - -# No parameters - behavior is controlled by configured plugin metadata: -# - ReleasePublishGuard (before Docker/Helm/GitHub/NuGet): optional branches, tag on HEAD, remote tag; sets skipPublishPlugins. -# - Publish plugins do not use per-plugin "branches"; centralize allowed branches on the guard. - -# Get the directory of the current script (for loading settings and relative paths) -$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path - -#region Import Modules - -$utilsDir = Split-Path $scriptDir -Parent - -# Import ScriptConfig module -$scriptConfigModulePath = Join-Path $utilsDir "ScriptConfig.psm1" -if (-not (Test-Path $scriptConfigModulePath)) { - Write-Error "ScriptConfig module not found at: $scriptConfigModulePath" - exit 1 -} - -Import-Module $scriptConfigModulePath -Force - -# Import Logging module -$loggingModulePath = Join-Path $utilsDir "Logging.psm1" -if (-not (Test-Path $loggingModulePath)) { - Write-Error "Logging module not found at: $loggingModulePath" - exit 1 -} - -Import-Module $loggingModulePath -Force -# Import PluginSupport module -$pluginSupportModulePath = Join-Path $scriptDir "PluginSupport.psm1" -if (-not (Test-Path $pluginSupportModulePath)) { - Write-Error "PluginSupport module not found at: $pluginSupportModulePath" - exit 1 -} - -Import-Module $pluginSupportModulePath -Force - -# Import ReleaseContext module (semver resolution for the engine) -$releaseContextModulePath = Join-Path $scriptDir "ReleaseContext.psm1" -if (-not (Test-Path $releaseContextModulePath)) { - Write-Error "ReleaseContext module not found at: $releaseContextModulePath" - exit 1 -} - -Import-Module $releaseContextModulePath -Force - -# Import EngineSupport module -$engineSupportModulePath = Join-Path $scriptDir "EngineSupport.psm1" -if (-not (Test-Path $engineSupportModulePath)) { - Write-Error "EngineSupport module not found at: $engineSupportModulePath" - exit 1 -} - -Import-Module $engineSupportModulePath -Force - -#endregion - -#region Load Settings -$settings = Get-ScriptSettings -ScriptDir $scriptDir -$configuredPlugins = Get-ConfiguredPlugins -Settings $settings - -#endregion - -#region Configuration - -$pluginsDir = Join-Path $scriptDir "CorePlugins" - -#endregion - -#endregion - -#region Main - -Write-Log -Level "STEP" -Message "==================================================" -Write-Log -Level "STEP" -Message "RELEASE ENGINE" -Write-Log -Level "STEP" -Message "==================================================" - -#region Preflight - -$plugins = $configuredPlugins -$engineContext = New-EngineContext -Plugins $plugins -ScriptDir $scriptDir -UtilsDir $utilsDir -Settings $settings -Write-Log -Level "OK" -Message "All pre-flight checks passed!" -$sharedPluginSettings = $engineContext - -#endregion - -#region Plugin Execution - -$releaseStageInitialized = $false -$releaseHadPluginFailures = $false - -if ($plugins.Count -eq 0) { - Write-Log -Level "WARN" -Message "No plugins configured in scriptsettings.json." -} -else { - for ($pluginIndex = 0; $pluginIndex -lt $plugins.Count; $pluginIndex++) { - $plugin = $plugins[$pluginIndex] - $pluginStageLabel = Get-PluginStageLabel -Plugin $plugin - - if ((Test-IsPublishPlugin -Plugin $plugin) -and -not $releaseStageInitialized) { - if (Test-PluginRunnable -Plugin $plugin -SharedSettings $sharedPluginSettings -PluginsDirectory $pluginsDir -WriteLogs:$false) { - $remainingPlugins = @($plugins[$pluginIndex..($plugins.Count - 1)]) - Initialize-ReleaseStageContext -RemainingPlugins $remainingPlugins -SharedSettings $sharedPluginSettings -ArtifactsDirectory $engineContext.artifactsDirectory -Version $engineContext.version - $releaseStageInitialized = $true - } - } - - $continueOnError = $false - $pluginSucceeded = Invoke-ConfiguredPlugin -Plugin $plugin -SharedSettings $sharedPluginSettings -PluginsDirectory $pluginsDir -ContinueOnError:$continueOnError - if (-not $pluginSucceeded) { - $releaseHadPluginFailures = $true - if (-not $continueOnError) { - break - } - } - } -} - -if (-not $releaseStageInitialized) { - $noReleasePluginsLogLevel = if ($engineContext.isNonReleaseBranch) { "INFO" } else { "WARN" } - Write-Log -Level $noReleasePluginsLogLevel -Message "No release-stage initialization ran (no enabled publish plugins reached, or none runnable)." -} - -#endregion - -#region Summary -Write-Log -Level "OK" -Message "==================================================" -if ($releaseHadPluginFailures) { - Write-Log -Level "ERROR" -Message "RELEASE FAILED" -} -elseif ($engineContext.PSObject.Properties.Name -contains 'skipPublishPlugins' -and $engineContext.skipPublishPlugins) { - Write-Log -Level "OK" -Message "RUN COMPLETE (publish skipped by ReleasePublishGuard)" -} -elseif ($engineContext.isNonReleaseBranch) { - Write-Log -Level "OK" -Message "NON-RELEASE RUN COMPLETE" -} -else { - Write-Log -Level "OK" -Message "RELEASE COMPLETE" -} -Write-Log -Level "OK" -Message "==================================================" - -if ($engineContext.isNonReleaseBranch -and -not ($engineContext.PSObject.Properties.Name -contains 'skipPublishPlugins' -and $engineContext.skipPublishPlugins)) { - $preferredReleaseBranch = Get-PreferredReleaseBranch -EngineContext $engineContext - Write-Log -Level "INFO" -Message "For publish, use an allowed branch (see ReleasePublishGuard.branches), e.g. '$preferredReleaseBranch', and satisfy the guard requirements." -} - -if ($releaseHadPluginFailures) { - exit 1 -} - -#endregion - -#endregion - diff --git a/utils/Run-Tests/CorePlugins/DotNetTest.psm1 b/utils/Run-Tests/CorePlugins/DotNetTest.psm1 deleted file mode 100644 index dba703e..0000000 --- a/utils/Run-Tests/CorePlugins/DotNetTest.psm1 +++ /dev/null @@ -1,98 +0,0 @@ -#requires -Version 7.0 -#requires -PSEdition Core - -<# -.SYNOPSIS - .NET test plugin for executing automated tests. - -.DESCRIPTION - Resolves one or more .NET test projects (`project` or `projects`), runs tests once - via TestRunner, then publishes metrics on the shared engine context for any later - plugin: `qualityLineCoverage`, `testResult`, `coverageLineRate` / `coverageBranchRate` / `coverageMethodRate`, - method counts, `testResultsDirectory`, `coverageCoberturaPaths`. Quality gates read - those keys generically (not tied to this plugin by name). Cobertura files are removed - after parsing unless TestRunner gains KeepResults. -#> - -if (-not (Get-Command Import-PluginDependency -ErrorAction SilentlyContinue)) { - $pluginSupportModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" - if (Test-Path $pluginSupportModulePath -PathType Leaf) { - # Same fallback pattern as the other plugins: use the existing shared module if it is already loaded. - Import-Module $pluginSupportModulePath -Force -Global -ErrorAction Stop - } -} - -function Invoke-Plugin { - param( - [Parameter(Mandatory = $true)] - $Settings - ) - - Import-PluginDependency -ModuleName "Logging" -RequiredCommand "Write-Log" - Import-PluginDependency -ModuleName "TestRunner" -RequiredCommand "Invoke-TestsWithCoverage" - - $pluginSettings = $Settings - $sharedSettings = $Settings.context - $testResultsDirSetting = $pluginSettings.resultsDir - $scriptDir = $sharedSettings.scriptDir - - $testProjectPaths = [System.Collections.Generic.List[string]]::new() - if ($pluginSettings.PSObject.Properties.Name -contains 'projects' -and $pluginSettings.projects) { - foreach ($rel in @($pluginSettings.projects)) { - if ([string]::IsNullOrWhiteSpace([string]$rel)) { continue } - $testProjectPaths.Add([System.IO.Path]::GetFullPath((Join-Path $scriptDir $rel.Trim()))) - } - } - if ($testProjectPaths.Count -eq 0 -and $pluginSettings.project) { - $testProjectPaths.Add([System.IO.Path]::GetFullPath((Join-Path $scriptDir $pluginSettings.project))) - } - if ($testProjectPaths.Count -eq 0) { - throw "DotNetTest plugin requires 'project' or 'projects' in scriptsettings.json." - } - - $testResultsDir = $null - if (-not [string]::IsNullOrWhiteSpace($testResultsDirSetting)) { - $testResultsDir = [System.IO.Path]::GetFullPath((Join-Path $scriptDir $testResultsDirSetting)) - } - elseif ($testProjectPaths.Count -gt 1) { - $testResultsDir = [System.IO.Path]::GetFullPath((Join-Path $scriptDir "TestResults")) - } - - Write-Log -Level "STEP" -Message "Running tests..." - - # Build a splatted hashtable so optional arguments can be added without duplicating the call site. - $invokeTestParams = @{ - TestProjectPath = @($testProjectPaths) - Silent = $true - } - if ($testResultsDir) { - $invokeTestParams.ResultsDirectory = $testResultsDir - } - - $testResult = Invoke-TestsWithCoverage @invokeTestParams - - if (-not $testResult.Success) { - throw "Tests failed. $($testResult.Error)" - } - - $sharedSettings | Add-Member -NotePropertyName testResult -NotePropertyValue $testResult -Force - $sharedSettings | Add-Member -NotePropertyName qualityLineCoverage -NotePropertyValue $testResult.LineRate -Force - $sharedSettings | Add-Member -NotePropertyName coverageLineRate -NotePropertyValue $testResult.LineRate -Force - $sharedSettings | Add-Member -NotePropertyName coverageBranchRate -NotePropertyValue $testResult.BranchRate -Force - $sharedSettings | Add-Member -NotePropertyName coverageMethodRate -NotePropertyValue $testResult.MethodRate -Force - $sharedSettings | Add-Member -NotePropertyName coverageTotalMethods -NotePropertyValue $testResult.TotalMethods -Force - $sharedSettings | Add-Member -NotePropertyName coverageCoveredMethods -NotePropertyValue $testResult.CoveredMethods -Force - if (($testResult.PSObject.Properties.Name -contains 'ResultsDirectory') -and $testResult.ResultsDirectory) { - $sharedSettings | Add-Member -NotePropertyName testResultsDirectory -NotePropertyValue $testResult.ResultsDirectory -Force - } - if ($testResult.CoverageFiles) { - $sharedSettings | Add-Member -NotePropertyName coverageCoberturaPaths -NotePropertyValue @($testResult.CoverageFiles) -Force - } - - Write-Log -Level "OK" -Message " All tests passed!" - Write-Log -Level "INFO" -Message " Line Coverage: $($testResult.LineRate)%" - Write-Log -Level "INFO" -Message " Branch Coverage: $($testResult.BranchRate)%" - Write-Log -Level "INFO" -Message " Method Coverage: $($testResult.MethodRate)%" -} - -Export-ModuleMember -Function Invoke-Plugin diff --git a/utils/Run-Tests/CorePlugins/QualityGate.psm1 b/utils/Run-Tests/CorePlugins/QualityGate.psm1 deleted file mode 100644 index 830c08b..0000000 --- a/utils/Run-Tests/CorePlugins/QualityGate.psm1 +++ /dev/null @@ -1,184 +0,0 @@ -#requires -Version 7.0 -#requires -PSEdition Core - -<# -.SYNOPSIS - Quality gate plugin (coverage threshold + optional .NET vulnerability scan). - -.DESCRIPTION - Does not run tests or collect coverage. It reads whatever prior plugins left on the - shared engine context (same object passed to every plugin as .context). - - Line coverage for threshold checks is resolved in order (first present wins): - - qualityLineCoverage (generic; any plugin may set this) - - coverageLineRate (conventional flat metric) - - testResult.LineRate (object from a test plugin; property name is conventional) - - Configure coverageThreshold > 0 to require one of those inputs. With coverageThreshold 0 - and scanVulnerabilities false, the plugin is a no-op. - - When scanVulnerabilities is true, runs dotnet list package --vulnerable on projectFiles. - - Use stageLabel "qualityGate" in scriptsettings.json; plugin module: CorePlugins/QualityGate.psm1 (`"name": "QualityGate"`). -#> - -if (-not (Get-Command Import-PluginDependency -ErrorAction SilentlyContinue)) { - $pluginSupportModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" - if (Test-Path $pluginSupportModulePath -PathType Leaf) { - Import-Module $pluginSupportModulePath -Force -Global -ErrorAction Stop - } -} - -function Test-VulnerablePackagesInternal { - param( - [Parameter(Mandatory = $true)] - [string[]]$ProjectFiles - ) - - $findings = @() - - foreach ($projectPath in $ProjectFiles) { - Write-Log -Level "STEP" -Message "Checking vulnerable packages: $([System.IO.Path]::GetFileName($projectPath))" - - $output = & dotnet list $projectPath package --vulnerable --include-transitive 2>&1 - if ($LASTEXITCODE -ne 0) { - throw "dotnet list package --vulnerable failed for $projectPath." - } - - $outputText = ($output | Out-String) - if ($outputText -match "(?im)\bhas the following vulnerable packages\b" -or $outputText -match "(?im)^\s*>\s+[A-Za-z0-9_.-]+\s") { - $findings += [pscustomobject]@{ - Project = $projectPath - Output = $outputText.Trim() - } - } - } - - return $findings -} - -function Get-LineCoveragePercentFromSharedContext { - param( - [Parameter(Mandatory = $true)] - $Shared - ) - - foreach ($prop in @('qualityLineCoverage', 'coverageLineRate')) { - if ($Shared.PSObject.Properties.Name -contains $prop) { - $raw = $Shared.$prop - if ($null -eq $raw) { continue } - $asString = [string]$raw - if ([string]::IsNullOrWhiteSpace($asString)) { continue } - return [double]$asString - } - } - - if ($Shared.PSObject.Properties.Name -contains 'testResult' -and $null -ne $Shared.testResult) { - $tr = $Shared.testResult - if ($tr.PSObject.Properties.Name -contains 'LineRate') { - return [double]$tr.LineRate - } - } - - return $null -} - -function Invoke-Plugin { - param( - [Parameter(Mandatory = $true)] - $Settings - ) - - Import-PluginDependency -ModuleName "Logging" -RequiredCommand "Write-Log" - Import-PluginDependency -ModuleName "ScriptConfig" -RequiredCommand "Assert-Command" - Import-PluginDependency -ModuleName "ReleaseContext" -RequiredCommand "Resolve-RelativePaths" - - $pluginSettings = $Settings - $sharedSettings = $Settings.context - $scriptDir = $sharedSettings.scriptDir - $coverageThresholdSetting = $pluginSettings.coverageThreshold - $failOnVulnerabilitiesSetting = $pluginSettings.failOnVulnerabilities - $scanVulnerabilities = $true - if ($null -ne $pluginSettings.scanVulnerabilities) { - $scanVulnerabilities = [bool]$pluginSettings.scanVulnerabilities - } - - if ($pluginSettings.PSObject.Properties['projectFiles'] -and $null -ne $pluginSettings.projectFiles) { - $projectFiles = @(Resolve-RelativePaths -Value $pluginSettings.projectFiles -BasePath $scriptDir) - } - elseif ($sharedSettings.PSObject.Properties['projectFiles'] -and $null -ne $sharedSettings.projectFiles) { - $projectFiles = @($sharedSettings.projectFiles) - } - else { - $projectFiles = @() - } - - $coverageThreshold = 0 - if ($null -ne $coverageThresholdSetting) { - $coverageThreshold = [double]$coverageThresholdSetting - } - - $needCoverageCheck = $coverageThreshold -gt 0 - if (-not $needCoverageCheck -and -not $scanVulnerabilities) { - Write-Log -Level "INFO" -Message " Quality gate: no checks enabled (coverageThreshold 0, scanVulnerabilities false)." - return - } - - $lineRate = $null - if ($needCoverageCheck) { - $lineRate = Get-LineCoveragePercentFromSharedContext -Shared $sharedSettings - if ($null -eq $lineRate) { - throw "coverageThreshold is $coverageThreshold but shared context has no line coverage. Set one of: qualityLineCoverage, coverageLineRate, or testResult.LineRate (from an earlier plugin)." - } - - Write-Log -Level "STEP" -Message "Checking line coverage threshold against shared context..." - if ($lineRate -lt $coverageThreshold) { - throw "Line coverage $lineRate% is below the configured threshold of $coverageThreshold%." - } - - Write-Log -Level "OK" -Message " Coverage threshold met: $lineRate% >= $coverageThreshold%" - } - else { - Write-Log -Level "INFO" -Message " Coverage threshold check not required (coverageThreshold is 0)." - } - - if (-not $scanVulnerabilities) { - Write-Log -Level "INFO" -Message " Vulnerability scan skipped (scanVulnerabilities is false)." - return - } - - Assert-Command dotnet - - $failOnVulnerabilities = $true - if ($null -ne $failOnVulnerabilitiesSetting) { - $failOnVulnerabilities = [bool]$failOnVulnerabilitiesSetting - } - - if ($projectFiles.Count -eq 0) { - throw "QualityGate requires projectFiles when scanVulnerabilities is true." - } - - $vulnerabilities = Test-VulnerablePackagesInternal -ProjectFiles $projectFiles - - if ($vulnerabilities.Count -eq 0) { - Write-Log -Level "OK" -Message " No vulnerable packages detected." - return - } - - foreach ($finding in $vulnerabilities) { - Write-Log -Level "WARN" -Message " Vulnerable packages detected in $([System.IO.Path]::GetFileName($finding.Project))" - $finding.Output -split "`r?`n" | ForEach-Object { - if (-not [string]::IsNullOrWhiteSpace($_)) { - Write-Log -Level "WARN" -Message " $_" - } - } - } - - if ($failOnVulnerabilities) { - throw "Vulnerable packages were detected and failOnVulnerabilities is enabled." - } - - Write-Log -Level "WARN" -Message "Vulnerable packages detected, but failOnVulnerabilities is disabled." -} - -Export-ModuleMember -Function Invoke-Plugin diff --git a/utils/Run-Tests/README.md b/utils/Run-Tests/README.md deleted file mode 100644 index db4c2a6..0000000 --- a/utils/Run-Tests/README.md +++ /dev/null @@ -1,58 +0,0 @@ -# Run Tests - -Plugin-driven test engine (same pattern as `src/Release-Package`). - -## Run - -```powershell -pwsh -File .\src\Run-Tests\Run-Tests.ps1 -``` - -Or: - -```bat -src\Run-Tests\Run-Tests.bat -``` - -## Core plugins - -| Plugin | Role | -|--------|------| -| `DotNetTest` | `dotnet test` + Coverlet Cobertura (`.NET` repos) | -| `NpmJestTest` | `npm test -- --coverage` + Jest `coverage-summary.json` | -| `QualityGate` | Optional line-coverage threshold from shared context | -| `CoverageBadges` | SVG badges for README (`assets/badges/`) | - -Configure plugin order and settings in `scriptsettings.json`. - -## Shared context - -Test plugins publish metrics for downstream plugins: - -- `qualityLineCoverage`, `coverageLineRate`, `coverageBranchRate`, `coverageMethodRate` -- `testResult` (full result object from `TestRunner`) - -`QualityGate` and `CoverageBadges` read these keys; they do not re-run tests. - -## npm/Jest example - -Replace `DotNetTest` with: - -```json -{ - "name": "NpmJestTest", - "stageLabel": "test", - "enabled": true, - "workspaceRoot": "..\\..\\src", - "testScript": "test", - "coverageDirectory": "coverage" -} -``` - -## Legacy entry point - -`src/Generate-CoverageBadges/Generate-CoverageBadges.ps1` forwards to this engine. - -## Custom plugins - -Add `CustomPlugins/YourPlugin.psm1` with `Invoke-Plugin`, then register it in `scriptsettings.json`. diff --git a/utils/Run-Tests/Run-Tests.bat b/utils/Run-Tests/Run-Tests.bat deleted file mode 100644 index 345b419..0000000 --- a/utils/Run-Tests/Run-Tests.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -pwsh -NoProfile -ExecutionPolicy Bypass -File "%~dp0Run-Tests.ps1" -pause diff --git a/utils/Run-Tests/Run-Tests.ps1 b/utils/Run-Tests/Run-Tests.ps1 deleted file mode 100644 index b58d3d5..0000000 --- a/utils/Run-Tests/Run-Tests.ps1 +++ /dev/null @@ -1,91 +0,0 @@ -#requires -Version 7.0 -#requires -PSEdition Core - -<# -.SYNOPSIS - Plugin-driven test and coverage engine. - -.DESCRIPTION - Loads scriptsettings.json, builds shared execution context, and runs configured - plugins in order. Each plugin implements Invoke-Plugin and receives its own - settings plus shared context on Settings.context. - -.USAGE - pwsh -File .\Run-Tests.ps1 -#> - -$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path -$utilsDir = Split-Path $scriptDir -Parent - -$scriptConfigModulePath = Join-Path $utilsDir "ScriptConfig.psm1" -if (-not (Test-Path $scriptConfigModulePath)) { - Write-Error "ScriptConfig module not found at: $scriptConfigModulePath" - exit 1 -} -Import-Module $scriptConfigModulePath -Force - -$loggingModulePath = Join-Path $utilsDir "Logging.psm1" -if (-not (Test-Path $loggingModulePath)) { - Write-Error "Logging module not found at: $loggingModulePath" - exit 1 -} -Import-Module $loggingModulePath -Force - -$pluginSupportModulePath = Join-Path $scriptDir "PluginSupport.psm1" -if (-not (Test-Path $pluginSupportModulePath)) { - Write-Error "PluginSupport module not found at: $pluginSupportModulePath" - exit 1 -} -Import-Module $pluginSupportModulePath -Force - -$engineSupportModulePath = Join-Path $scriptDir "EngineSupport.psm1" -if (-not (Test-Path $engineSupportModulePath)) { - Write-Error "EngineSupport module not found at: $engineSupportModulePath" - exit 1 -} -Import-Module $engineSupportModulePath -Force - -$releaseContextModulePath = Join-Path $utilsDir "Release-Package\ReleaseContext.psm1" -if (-not (Test-Path $releaseContextModulePath)) { - Write-Error "ReleaseContext module not found at: $releaseContextModulePath" - exit 1 -} -Import-Module $releaseContextModulePath -Force - -$settings = Get-ScriptSettings -ScriptDir $scriptDir -$configuredPlugins = Get-ConfiguredPlugins -Settings $settings -$pluginsDir = Join-Path $scriptDir "CorePlugins" - -Write-Log -Level "STEP" -Message "==================================================" -Write-Log -Level "STEP" -Message "TEST ENGINE" -Write-Log -Level "STEP" -Message "==================================================" - -$engineContext = New-EngineContext -ScriptDir $scriptDir -UtilsDir $utilsDir -Settings $settings - -if ($configuredPlugins.Count -eq 0) { - Write-Log -Level "WARN" -Message "No plugins configured in scriptsettings.json." - exit 0 -} - -$testHadPluginFailures = $false - -foreach ($plugin in $configuredPlugins) { - $pluginSucceeded = Invoke-ConfiguredPlugin -Plugin $plugin -SharedSettings $engineContext -PluginsDirectory $pluginsDir -ContinueOnError:$false - if (-not $pluginSucceeded) { - $testHadPluginFailures = $true - break - } -} - -Write-Log -Level "OK" -Message "==================================================" -if ($testHadPluginFailures) { - Write-Log -Level "ERROR" -Message "TEST RUN FAILED" -} -else { - Write-Log -Level "OK" -Message "TEST RUN COMPLETE" -} -Write-Log -Level "OK" -Message "==================================================" - -if ($testHadPluginFailures) { - exit 1 -} diff --git a/utils/Update-RepoUtils/Update-RepoUtils.bat b/utils/Update-RepoUtils/Update-RepoUtils.bat deleted file mode 100644 index 8ff94ac..0000000 --- a/utils/Update-RepoUtils/Update-RepoUtils.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -pwsh -NoProfile -ExecutionPolicy Bypass -File "%~dp0Update-RepoUtils.ps1" -pause diff --git a/utils/src/Force-AmendTaggedCommit.bat b/utils/src/Force-AmendTaggedCommit.bat new file mode 100644 index 0000000..67b7d76 --- /dev/null +++ b/utils/src/Force-AmendTaggedCommit.bat @@ -0,0 +1,3 @@ +@echo off +pwsh -NoProfile -ExecutionPolicy Bypass -File "%~dp0tools\Force-AmendTaggedCommit\Force-AmendTaggedCommit.ps1" %* +pause diff --git a/utils/src/Invoke-ReleasePackage.bat b/utils/src/Invoke-ReleasePackage.bat new file mode 100644 index 0000000..85d776a --- /dev/null +++ b/utils/src/Invoke-ReleasePackage.bat @@ -0,0 +1,3 @@ +@echo off +pwsh -NoProfile -ExecutionPolicy Bypass -File "%~dp0engines\release\Invoke-ReleasePackage.ps1" %* +pause diff --git a/utils/src/Invoke-TestEngine.bat b/utils/src/Invoke-TestEngine.bat new file mode 100644 index 0000000..0cfd13f --- /dev/null +++ b/utils/src/Invoke-TestEngine.bat @@ -0,0 +1,3 @@ +@echo off +pwsh -NoProfile -ExecutionPolicy Bypass -File "%~dp0engines\test\Invoke-TestEngine.ps1" %* +pause diff --git a/utils/src/Update-RepoUtils.bat b/utils/src/Update-RepoUtils.bat new file mode 100644 index 0000000..048e3fb --- /dev/null +++ b/utils/src/Update-RepoUtils.bat @@ -0,0 +1,3 @@ +@echo off +pwsh -NoProfile -ExecutionPolicy Bypass -File "%~dp0tools\Update-RepoUtils\Update-RepoUtils.ps1" %* +pause diff --git a/utils/src/engines/release/Invoke-ReleasePackage.ps1 b/utils/src/engines/release/Invoke-ReleasePackage.ps1 new file mode 100644 index 0000000..caf880e --- /dev/null +++ b/utils/src/engines/release/Invoke-ReleasePackage.ps1 @@ -0,0 +1,80 @@ +#requires -Version 7.0 +#requires -PSEdition Core + +<# +.SYNOPSIS + Plugin-driven release engine entry script. +#> + +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$srcDir = (Resolve-Path (Join-Path $scriptDir '..\..')).Path + +. (Join-Path $srcDir 'modules/Engine/Import-EngineModules.ps1') +Import-EngineModules -Engine Release + +$settings = Get-ScriptSettings -ScriptDir $scriptDir +$configuredPlugins = Get-ConfiguredPlugins -Settings $settings + +Write-Log -Level 'STEP' -Message '==================================================' +Write-Log -Level 'STEP' -Message 'RELEASE ENGINE' +Write-Log -Level 'STEP' -Message '==================================================' + +$plugins = $configuredPlugins +$engineContext = New-EngineContext -Plugins $plugins -ScriptDir $scriptDir -SrcDir $srcDir -Settings $settings +Write-Log -Level 'OK' -Message 'All pre-flight checks passed!' +$sharedPluginSettings = $engineContext + +$releaseStageInitialized = $false +$releaseHadPluginFailures = $false + +if ($plugins.Count -eq 0) { + Write-Log -Level 'WARN' -Message 'No plugins configured in scriptSettings.json.' +} +else { + for ($pluginIndex = 0; $pluginIndex -lt $plugins.Count; $pluginIndex++) { + $plugin = $plugins[$pluginIndex] + + if ((Test-IsPublishPlugin -Plugin $plugin) -and -not $releaseStageInitialized) { + if (Test-PluginRunnable -Plugin $plugin -SharedSettings $sharedPluginSettings -EngineDirectory $scriptDir -WriteLogs:$false) { + $remainingPlugins = @($plugins[$pluginIndex..($plugins.Count - 1)]) + Initialize-ReleaseStageContext -RemainingPlugins $remainingPlugins -SharedSettings $sharedPluginSettings -ArtifactsDirectory $engineContext.artifactsDirectory -Version $engineContext.version + $releaseStageInitialized = $true + } + } + + $pluginSucceeded = Invoke-ConfiguredPlugin -Plugin $plugin -SharedSettings $sharedPluginSettings -EngineDirectory $scriptDir -ContinueOnError:$false + if (-not $pluginSucceeded) { + $releaseHadPluginFailures = $true + break + } + } +} + +if (-not $releaseStageInitialized) { + $noReleasePluginsLogLevel = if ($engineContext.isNonReleaseBranch) { 'INFO' } else { 'WARN' } + Write-Log -Level $noReleasePluginsLogLevel -Message 'No release-stage initialization ran (no enabled publish plugins reached, or none runnable).' +} + +Write-Log -Level 'OK' -Message '==================================================' +if ($releaseHadPluginFailures) { + Write-Log -Level 'ERROR' -Message 'RELEASE FAILED' +} +elseif ($engineContext.PSObject.Properties.Name -contains 'skipPublishPlugins' -and $engineContext.skipPublishPlugins) { + Write-Log -Level 'OK' -Message 'RUN COMPLETE (publish skipped by ReleasePublishGuard)' +} +elseif ($engineContext.isNonReleaseBranch) { + Write-Log -Level 'OK' -Message 'NON-RELEASE RUN COMPLETE' +} +else { + Write-Log -Level 'OK' -Message 'RELEASE COMPLETE' +} +Write-Log -Level 'OK' -Message '==================================================' + +if ($engineContext.isNonReleaseBranch -and -not ($engineContext.PSObject.Properties.Name -contains 'skipPublishPlugins' -and $engineContext.skipPublishPlugins)) { + $preferredReleaseBranch = Get-PreferredReleaseBranch -EngineContext $engineContext + Write-Log -Level 'INFO' -Message "For publish, use an allowed branch (see ReleasePublishGuard.branches), e.g. '$preferredReleaseBranch', and satisfy the guard requirements." +} + +if ($releaseHadPluginFailures) { + exit 1 +} diff --git a/utils/Release-Package/CustomPlugins/.gitkeep b/utils/src/engines/release/custom/.gitkeep similarity index 100% rename from utils/Release-Package/CustomPlugins/.gitkeep rename to utils/src/engines/release/custom/.gitkeep diff --git a/utils/Release-Package/scriptsettings.json b/utils/src/engines/release/scriptSettings.json similarity index 90% rename from utils/Release-Package/scriptsettings.json rename to utils/src/engines/release/scriptSettings.json index 852fccf..4848d5a 100644 --- a/utils/Release-Package/scriptsettings.json +++ b/utils/src/engines/release/scriptSettings.json @@ -7,14 +7,14 @@ "name": "NpmReleaseVersion", "stageLabel": "build", "enabled": true, - "packageJsonPath": "..\\..\\src\\package.json", + "packageJsonPath": "..\\..\\..\\..\\src\\package.json", "syncWorkspaceVersions": true }, { "name": "NpmBuild", "stageLabel": "build", "enabled": true, - "workspaceRoot": "..\\..\\src", + "workspaceRoot": "..\\..\\..\\..\\src", "useCi": true, "buildScript": "build" }, @@ -39,7 +39,7 @@ "npmApiKey": "NPMJS_MAKS_IT", "registry": "https://registry.npmjs.org", "access": "public", - "workspaceRoot": "..\\..\\src", + "workspaceRoot": "..\\..\\..\\..\\src", "publishOrder": [ "@maks-it.com/webui-contracts", "@maks-it.com/webui-core", @@ -53,7 +53,7 @@ "NpmBuild": "Runs npm ci + npm run build in workspaceRoot.", "ReleasePublishGuard": "Place before NpmPublish. tagVersionMustMatchReleaseVersion compares git tag on HEAD to NpmReleaseVersion.", "NpmPublish": "npmApiKey is the environment variable name holding the npm automation token (NPMJS_MAKS_IT). publishOrder must follow dependency order.", - "maksit-repoutils": "Engine docs: https://github.com/MAKS-IT-COM/maksit-repoutils (src/Release-Package/README.md)." + "maksit-repoutils": "Engine docs: https://github.com/MAKS-IT-COM/maksit-repoutils (src/engines/release/README.md)." } } } diff --git a/utils/src/engines/test/Invoke-TestEngine.ps1 b/utils/src/engines/test/Invoke-TestEngine.ps1 new file mode 100644 index 0000000..f4da98e --- /dev/null +++ b/utils/src/engines/test/Invoke-TestEngine.ps1 @@ -0,0 +1,50 @@ +#requires -Version 7.0 +#requires -PSEdition Core + +<# +.SYNOPSIS + Plugin-driven test and coverage engine entry script. +#> + +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$srcDir = (Resolve-Path (Join-Path $scriptDir '..\..')).Path + +. (Join-Path $srcDir 'modules/Engine/Import-EngineModules.ps1') +Import-EngineModules -Engine Test + +$settings = Get-ScriptSettings -ScriptDir $scriptDir +$configuredPlugins = Get-ConfiguredPlugins -Settings $settings + +Write-Log -Level 'STEP' -Message '==================================================' +Write-Log -Level 'STEP' -Message 'TEST ENGINE' +Write-Log -Level 'STEP' -Message '==================================================' + +$engineContext = New-EngineContext -ScriptDir $scriptDir -SrcDir $srcDir -Settings $settings + +if ($configuredPlugins.Count -eq 0) { + Write-Log -Level 'WARN' -Message 'No plugins configured in scriptSettings.json.' + exit 0 +} + +$testHadPluginFailures = $false + +foreach ($plugin in $configuredPlugins) { + $pluginSucceeded = Invoke-ConfiguredPlugin -Plugin $plugin -SharedSettings $engineContext -EngineDirectory $scriptDir -ContinueOnError:$false + if (-not $pluginSucceeded) { + $testHadPluginFailures = $true + break + } +} + +Write-Log -Level 'OK' -Message '==================================================' +if ($testHadPluginFailures) { + Write-Log -Level 'ERROR' -Message 'TEST RUN FAILED' +} +else { + Write-Log -Level 'OK' -Message 'TEST RUN COMPLETE' +} +Write-Log -Level 'OK' -Message '==================================================' + +if ($testHadPluginFailures) { + exit 1 +} diff --git a/utils/Run-Tests/CustomPlugins/.gitkeep b/utils/src/engines/test/custom/.gitkeep similarity index 100% rename from utils/Run-Tests/CustomPlugins/.gitkeep rename to utils/src/engines/test/custom/.gitkeep diff --git a/utils/Run-Tests/scriptsettings.json b/utils/src/engines/test/scriptSettings.json similarity index 91% rename from utils/Run-Tests/scriptsettings.json rename to utils/src/engines/test/scriptSettings.json index 34158dc..cf86787 100644 --- a/utils/Run-Tests/scriptsettings.json +++ b/utils/src/engines/test/scriptSettings.json @@ -3,14 +3,14 @@ "title": "Run Tests Script Settings", "description": "maksit-webui: plugin-driven Jest tests and coverage badges.", "paths": { - "badgesDir": "..\\..\\assets\\badges" + "badgesDir": "..\\..\\..\\..\\assets\\badges" }, "plugins": [ { "name": "NpmJestTest", "stageLabel": "test", "enabled": true, - "workspaceRoot": "..\\..\\src", + "workspaceRoot": "..\\..\\..\\..\\src", "testScript": "test", "coverageDirectory": "coverage" }, @@ -25,7 +25,7 @@ "name": "CoverageBadges", "stageLabel": "report", "enabled": true, - "badgesDir": "..\\..\\assets\\badges", + "badgesDir": "..\\..\\..\\..\\assets\\badges", "badges": [ { "name": "coverage-lines.svg", diff --git a/utils/ChangelogSupport.psm1 b/utils/src/modules/ChangelogSupport.psm1 similarity index 100% rename from utils/ChangelogSupport.psm1 rename to utils/src/modules/ChangelogSupport.psm1 diff --git a/utils/Release-Package/ReleaseContext.psm1 b/utils/src/modules/Engine/EngineContext.psm1 similarity index 96% rename from utils/Release-Package/ReleaseContext.psm1 rename to utils/src/modules/Engine/EngineContext.psm1 index c92fb06..9d397d1 100644 --- a/utils/Release-Package/ReleaseContext.psm1 +++ b/utils/src/modules/Engine/EngineContext.psm1 @@ -3,7 +3,7 @@ <# .SYNOPSIS - Helpers to resolve release semver from plugin configuration. + Helpers to resolve engine semver and relative paths from plugin configuration. .DESCRIPTION Used by New-EngineContext and version plugins: @@ -119,7 +119,7 @@ function Resolve-DotNetReleaseVersion { $releaseVersionPlugin = @($Plugins | Where-Object { $_.name -eq 'DotNetReleaseVersion' } | Select-Object -First 1) if ($releaseVersionPlugin.Count -eq 0 -or $null -eq $releaseVersionPlugin[0]) { - Write-Error "Configure a DotNetReleaseVersion plugin in scriptsettings.json with projectFiles." + Write-Error "Configure a DotNetReleaseVersion plugin in scriptSettings.json with projectFiles." exit 1 } @@ -151,7 +151,7 @@ function Resolve-NpmReleaseVersion { $releaseVersionPlugin = @($Plugins | Where-Object { $_.name -eq 'NpmReleaseVersion' } | Select-Object -First 1) if ($releaseVersionPlugin.Count -eq 0 -or $null -eq $releaseVersionPlugin[0]) { - Write-Error "Configure an NpmReleaseVersion plugin in scriptsettings.json with packageJsonPath." + Write-Error "Configure an NpmReleaseVersion plugin in scriptSettings.json with packageJsonPath." exit 1 } @@ -215,7 +215,7 @@ function Resolve-ReleaseVersion { return Resolve-NpmReleaseVersion -Plugins $Plugins -ScriptDir $ScriptDir } - Write-Error "Configure a DotNetReleaseVersion plugin (projectFiles) or NpmReleaseVersion plugin (packageJsonPath) in scriptsettings.json." + Write-Error "Configure a DotNetReleaseVersion plugin (projectFiles) or NpmReleaseVersion plugin (packageJsonPath) in scriptSettings.json." exit 1 } diff --git a/utils/src/modules/Engine/Import-EngineModules.ps1 b/utils/src/modules/Engine/Import-EngineModules.ps1 new file mode 100644 index 0000000..5c43ed7 --- /dev/null +++ b/utils/src/modules/Engine/Import-EngineModules.ps1 @@ -0,0 +1,35 @@ +#requires -Version 7.0 +#requires -PSEdition Core + +function Import-EngineModules { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [ValidateSet('Release', 'Test')] + [string]$Engine + ) + + $engineModuleDir = $PSScriptRoot + $modulesDir = Split-Path $engineModuleDir -Parent + $supportModules = @( + (Join-Path $modulesDir 'ScriptConfig.psm1'), + (Join-Path $modulesDir 'Logging.psm1'), + (Join-Path $engineModuleDir 'PluginSupport.psm1'), + (Join-Path $engineModuleDir 'EngineContext.psm1') + ) + + if ($Engine -eq 'Release') { + $supportModules += (Join-Path $engineModuleDir 'ReleaseSupport.psm1') + } + else { + $supportModules += (Join-Path $engineModuleDir 'TestSupport.psm1') + } + + foreach ($modulePath in $supportModules) { + if (-not (Test-Path $modulePath -PathType Leaf)) { + throw "Required module not found at: $modulePath" + } + + Import-Module $modulePath -Force + } +} diff --git a/utils/Run-Tests/PluginSupport.psm1 b/utils/src/modules/Engine/PluginSupport.psm1 similarity index 85% rename from utils/Run-Tests/PluginSupport.psm1 rename to utils/src/modules/Engine/PluginSupport.psm1 index b86e733..30371ea 100644 --- a/utils/Run-Tests/PluginSupport.psm1 +++ b/utils/src/modules/Engine/PluginSupport.psm1 @@ -1,8 +1,16 @@ #requires -Version 7.0 #requires -PSEdition Core +function Get-RepoUtilsSrcDirectory { + return (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) +} + +function Get-RepoUtilsModulesDirectory { + return Split-Path $PSScriptRoot -Parent +} + if (-not (Get-Command Write-Log -ErrorAction SilentlyContinue)) { - $loggingModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "Logging.psm1" + $loggingModulePath = Join-Path (Get-RepoUtilsModulesDirectory) "Logging.psm1" if (Test-Path $loggingModulePath -PathType Leaf) { Import-Module $loggingModulePath -Force } @@ -21,11 +29,14 @@ function Import-PluginDependency { return } - $moduleRoot = Split-Path $PSScriptRoot -Parent - $modulePath = Join-Path $moduleRoot "$ModuleName.psm1" + $modulesDir = Get-RepoUtilsModulesDirectory + $engineModuleDir = $PSScriptRoot + $modulePath = Join-Path $modulesDir "$ModuleName.psm1" + if (-not (Test-Path $modulePath -PathType Leaf)) { + $modulePath = Join-Path $engineModuleDir "$ModuleName.psm1" + } + if (Test-Path $modulePath -PathType Leaf) { - # Import into the global session so the calling plugin can see the exported commands. - # Importing only into this module's scope would make the dependency invisible to the plugin. Import-Module $modulePath -Force -Global -ErrorAction Stop } @@ -44,8 +55,6 @@ function Get-ConfiguredPlugins { return @() } - # JSON can deserialize a single plugin as one object or multiple plugins as an array. - # Always return an array so the engine can loop without special-case logic. if ($Settings.plugins -is [System.Collections.IEnumerable] -and -not ($Settings.plugins -is [string])) { return @($Settings.plugins) } @@ -76,7 +85,6 @@ function Get-PluginBranches { return @() } - # Strings are also IEnumerable in PowerShell, so exclude them or we would split into characters. if ($Plugin.branches -is [System.Collections.IEnumerable] -and -not ($Plugin.branches -is [string])) { return @($Plugin.branches | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) } @@ -119,7 +127,7 @@ function Test-IsPublishPlugin { return $false } - return @('GitHub', 'DotNetNuGet', 'DockerPush', 'HelmPush', 'NpmPublish') -contains ([string]$Plugin.name) + return @('GitHub', 'DotNetNuGet', 'DotNetDockerPush', 'DotNetHelmPush', 'NpmPublish') -contains ([string]$Plugin.name) } function Get-PluginSettingValue { @@ -174,7 +182,6 @@ function Get-PluginPathListSetting { return @() } - # Same rule as above: treat a string as one path, not a char-by-char sequence. if ($value -is [System.Collections.IEnumerable] -and -not ($value -is [string])) { $rawPaths += $value } @@ -191,7 +198,6 @@ function Get-PluginPathListSetting { $resolvedPaths += [System.IO.Path]::GetFullPath((Join-Path $BasePath ([string]$path))) } - # Wrap again to stop PowerShell from unrolling a single-item array into a bare string. return @($resolvedPaths) } @@ -251,13 +257,17 @@ function Resolve-PluginModulePath { $Plugin, [Parameter(Mandatory = $true)] - [string]$PluginsDirectory + [string]$EngineDirectory ) + $srcDir = Split-Path (Split-Path $EngineDirectory -Parent) -Parent + $pluginsRoot = Join-Path $srcDir "plugins" $pluginFileName = "{0}.psm1" -f $Plugin.name $candidatePaths = @( - (Join-Path $PluginsDirectory $pluginFileName), - (Join-Path (Join-Path (Split-Path $PluginsDirectory -Parent) "CustomPlugins") $pluginFileName) + (Join-Path (Join-Path $EngineDirectory "custom") $pluginFileName), + (Join-Path (Join-Path $pluginsRoot "Platform") $pluginFileName), + (Join-Path (Join-Path $pluginsRoot "DotNet") $pluginFileName), + (Join-Path (Join-Path $pluginsRoot "Npm") $pluginFileName) ) foreach ($candidatePath in $candidatePaths) { @@ -278,7 +288,7 @@ function Test-PluginRunnable { [psobject]$SharedSettings, [Parameter(Mandatory = $true)] - [string]$PluginsDirectory, + [string]$EngineDirectory, [Parameter(Mandatory = $false)] [bool]$WriteLogs = $true @@ -298,7 +308,7 @@ function Test-PluginRunnable { return $false } - $pluginModulePath = Resolve-PluginModulePath -Plugin $Plugin -PluginsDirectory $PluginsDirectory + $pluginModulePath = Resolve-PluginModulePath -Plugin $Plugin -EngineDirectory $EngineDirectory if (-not (Test-Path $pluginModulePath -PathType Leaf)) { if ($WriteLogs) { Write-Log -Level "ERROR" -Message "Plugin module not found: $pluginModulePath" @@ -323,7 +333,6 @@ function New-PluginInvocationSettings { $properties[$property.Name] = $property.Value } - # Plugins receive their own config plus shared runtime context. $properties['context'] = $SharedSettings return [pscustomobject]$properties } @@ -337,13 +346,13 @@ function Invoke-ConfiguredPlugin { [psobject]$SharedSettings, [Parameter(Mandatory = $true)] - [string]$PluginsDirectory, + [string]$EngineDirectory, [Parameter(Mandatory = $false)] [bool]$ContinueOnError = $false ) - if (-not (Test-PluginRunnable -Plugin $Plugin -SharedSettings $SharedSettings -PluginsDirectory $PluginsDirectory -WriteLogs:$true)) { + if (-not (Test-PluginRunnable -Plugin $Plugin -SharedSettings $SharedSettings -EngineDirectory $EngineDirectory -WriteLogs:$true)) { if ($Plugin.enabled) { return $false } @@ -356,13 +365,11 @@ function Invoke-ConfiguredPlugin { return $true } - $pluginModulePath = Resolve-PluginModulePath -Plugin $Plugin -PluginsDirectory $PluginsDirectory + $pluginModulePath = Resolve-PluginModulePath -Plugin $Plugin -EngineDirectory $EngineDirectory Write-Log -Level "STEP" -Message "Running plugin '$($Plugin.name)'..." try { $moduleInfo = Import-Module $pluginModulePath -Force -PassThru -ErrorAction Stop - # Resolve Invoke-Plugin from the imported module explicitly so we call the plugin we just loaded, - # not some command with the same name from another module already in session. $invokeCommand = Get-Command -Name "Invoke-Plugin" -Module $moduleInfo.Name -ErrorAction Stop $pluginSettings = New-PluginInvocationSettings -Plugin $Plugin -SharedSettings $SharedSettings diff --git a/utils/Release-Package/EngineSupport.psm1 b/utils/src/modules/Engine/ReleaseSupport.psm1 similarity index 89% rename from utils/Release-Package/EngineSupport.psm1 rename to utils/src/modules/Engine/ReleaseSupport.psm1 index 048192a..ffda8d7 100644 --- a/utils/Release-Package/EngineSupport.psm1 +++ b/utils/src/modules/Engine/ReleaseSupport.psm1 @@ -1,15 +1,17 @@ #requires -Version 7.0 #requires -PSEdition Core +$modulesDir = Split-Path $PSScriptRoot -Parent + if (-not (Get-Command Write-Log -ErrorAction SilentlyContinue)) { - $loggingModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "Logging.psm1" + $loggingModulePath = Join-Path $modulesDir "Logging.psm1" if (Test-Path $loggingModulePath -PathType Leaf) { Import-Module $loggingModulePath -Force } } if (-not (Get-Command Get-CurrentBranch -ErrorAction SilentlyContinue)) { - $gitToolsModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "GitTools.psm1" + $gitToolsModulePath = Join-Path $modulesDir "GitTools.psm1" if (Test-Path $gitToolsModulePath -PathType Leaf) { Import-Module $gitToolsModulePath -Force } @@ -23,9 +25,9 @@ if (-not (Get-Command Get-PluginStageLabel -ErrorAction SilentlyContinue) -or -n } if (-not (Get-Command Resolve-ReleaseVersion -ErrorAction SilentlyContinue)) { - $releaseContextModulePath = Join-Path $PSScriptRoot "ReleaseContext.psm1" - if (Test-Path $releaseContextModulePath -PathType Leaf) { - Import-Module $releaseContextModulePath -Force + $engineContextModulePath = Join-Path $PSScriptRoot "EngineContext.psm1" + if (Test-Path $engineContextModulePath -PathType Leaf) { + Import-Module $engineContextModulePath -Force } } @@ -73,7 +75,7 @@ function New-EngineContext { [string]$ScriptDir, [Parameter(Mandatory = $true)] - [string]$UtilsDir, + [string]$SrcDir, [Parameter(Mandatory = $false)] [psobject]$Settings @@ -82,11 +84,11 @@ function New-EngineContext { $resolvedVersion = Resolve-ReleaseVersion -Plugins $Plugins -ScriptDir $ScriptDir $version = $resolvedVersion.version $versionSource = $resolvedVersion.source - $artifactsDirectory = [System.IO.Path]::GetFullPath((Join-Path $ScriptDir '..\\..\\release')) + $releaseRelative = '..\..\..\release' + $artifactsDirectory = [System.IO.Path]::GetFullPath((Join-Path $ScriptDir $releaseRelative)) $currentBranch = Get-CurrentBranch - # Hint branches for messaging: ReleasePublishGuard.branches if present, else publish plugins' branches, else main. $releaseBranches = @() foreach ($p in $Plugins) { if (-not $p.enabled) { continue } @@ -119,7 +121,8 @@ function New-EngineContext { return [pscustomobject]@{ scriptDir = $ScriptDir - utilsDir = $UtilsDir + srcDir = $SrcDir + utilsDir = $SrcDir currentBranch = $currentBranch version = $version tag = $tag @@ -146,6 +149,3 @@ function Get-PreferredReleaseBranch { } Export-ModuleMember -Function Assert-WorkingTreeClean, Initialize-ReleaseStageContext, New-EngineContext, Get-PreferredReleaseBranch - - - diff --git a/utils/Run-Tests/EngineSupport.psm1 b/utils/src/modules/Engine/TestSupport.psm1 similarity index 81% rename from utils/Run-Tests/EngineSupport.psm1 rename to utils/src/modules/Engine/TestSupport.psm1 index 7233e17..a90d03d 100644 --- a/utils/Run-Tests/EngineSupport.psm1 +++ b/utils/src/modules/Engine/TestSupport.psm1 @@ -1,8 +1,10 @@ #requires -Version 7.0 #requires -PSEdition Core +$modulesDir = Split-Path $PSScriptRoot -Parent + if (-not (Get-Command Write-Log -ErrorAction SilentlyContinue)) { - $loggingModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "Logging.psm1" + $loggingModulePath = Join-Path $modulesDir "Logging.psm1" if (Test-Path $loggingModulePath -PathType Leaf) { Import-Module $loggingModulePath -Force } @@ -14,7 +16,7 @@ function New-EngineContext { [string]$ScriptDir, [Parameter(Mandatory = $true)] - [string]$UtilsDir, + [string]$SrcDir, [Parameter(Mandatory = $false)] [psobject]$Settings @@ -27,7 +29,8 @@ function New-EngineContext { return [pscustomobject]@{ scriptDir = $ScriptDir - utilsDir = $UtilsDir + srcDir = $SrcDir + utilsDir = $SrcDir badgesDir = $badgesDir } } diff --git a/utils/GitTools.psm1 b/utils/src/modules/GitTools.psm1 similarity index 90% rename from utils/GitTools.psm1 rename to utils/src/modules/GitTools.psm1 index 405f408..be56c94 100644 --- a/utils/GitTools.psm1 +++ b/utils/src/modules/GitTools.psm1 @@ -76,7 +76,7 @@ function Invoke-GitInternal { # Used by: # - utils/Release-NuGetPackage/Release-NuGetPackage.ps1 -# - utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 +# - tools/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 # Purpose: # - Resolve and print the current branch name. function Get-CurrentBranch { @@ -89,7 +89,7 @@ function Get-CurrentBranch { # Used by: # - utils/Release-NuGetPackage/Release-NuGetPackage.ps1 -# - utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 +# - tools/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 # Purpose: # - Return `git status --short` output for pending-change checks. function Get-GitStatusShort { @@ -112,7 +112,7 @@ function Get-CurrentCommitTag { } # Used by: -# - utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 +# - tools/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 # Purpose: # - Get all tag names pointing at HEAD. function Get-HeadTags { @@ -144,7 +144,7 @@ function Test-RemoteTagExists { # Used by: # - utils/Release-NuGetPackage/Release-NuGetPackage.ps1 -# - utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 +# - tools/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 # Purpose: # - Push tag to remote (optionally with `--force`). function Push-TagToRemote { @@ -169,7 +169,7 @@ function Push-TagToRemote { } # Used by: -# - utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 +# - tools/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 # Purpose: # - Push branch to remote (optionally with `--force`). function Push-BranchToRemote { @@ -194,7 +194,7 @@ function Push-BranchToRemote { } # Used by: -# - utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 +# - tools/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 # Purpose: # - Get HEAD commit hash. function Get-HeadCommitHash { @@ -208,7 +208,7 @@ function Get-HeadCommitHash { } # Used by: -# - utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 +# - tools/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 # Purpose: # - Get HEAD commit subject line. function Get-HeadCommitMessage { @@ -216,7 +216,7 @@ function Get-HeadCommitMessage { } # Used by: -# - utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 +# - tools/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 # Purpose: # - Stage all changes (tracked, untracked, deletions). function Add-AllChanges { @@ -224,7 +224,7 @@ function Add-AllChanges { } # Used by: -# - utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 +# - tools/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 # Purpose: # - Amend HEAD commit and keep existing commit message. function Update-HeadCommitNoEdit { @@ -232,7 +232,7 @@ function Update-HeadCommitNoEdit { } # Used by: -# - utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 +# - tools/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 # Purpose: # - Delete local tag. function Remove-LocalTag { @@ -245,7 +245,7 @@ function Remove-LocalTag { } # Used by: -# - utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 +# - tools/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 # Purpose: # - Create local tag. function New-LocalTag { @@ -258,7 +258,7 @@ function New-LocalTag { } # Used by: -# - utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 +# - tools/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 # Purpose: # - Get HEAD one-line commit info. function Get-HeadCommitOneLine { diff --git a/utils/Logging.psm1 b/utils/src/modules/Logging.psm1 similarity index 100% rename from utils/Logging.psm1 rename to utils/src/modules/Logging.psm1 diff --git a/utils/ScriptConfig.psm1 b/utils/src/modules/ScriptConfig.psm1 similarity index 93% rename from utils/ScriptConfig.psm1 rename to utils/src/modules/ScriptConfig.psm1 index 738cd5c..26bd953 100644 --- a/utils/ScriptConfig.psm1 +++ b/utils/src/modules/ScriptConfig.psm1 @@ -7,7 +7,7 @@ function Get-ScriptSettings { [string]$ScriptDir, [Parameter(Mandatory = $false)] - [string]$SettingsFileName = "scriptsettings.json" + [string]$SettingsFileName = "scriptSettings.json" ) $settingsPath = Join-Path $ScriptDir $SettingsFileName diff --git a/utils/TestRunner.psm1 b/utils/src/modules/TestRunner.psm1 similarity index 100% rename from utils/TestRunner.psm1 rename to utils/src/modules/TestRunner.psm1 diff --git a/utils/Release-Package/CorePlugins/CleanupArtifacts.psm1 b/utils/src/plugins/DotNet/DotNetCleanupArtifacts.psm1 similarity index 85% rename from utils/Release-Package/CorePlugins/CleanupArtifacts.psm1 rename to utils/src/plugins/DotNet/DotNetCleanupArtifacts.psm1 index 0a78b9c..bbc7459 100644 --- a/utils/Release-Package/CorePlugins/CleanupArtifacts.psm1 +++ b/utils/src/plugins/DotNet/DotNetCleanupArtifacts.psm1 @@ -3,16 +3,17 @@ <# .SYNOPSIS - Cleanup plugin for removing generated artifacts after pipeline completion. + .NET artifact cleanup plugin — remove NuGet build outputs after release. .DESCRIPTION - This plugin removes files from the configured artifacts directory using - glob patterns. It is typically placed at the end of the Release stage so - cleanup becomes explicit and opt-in per repository. + Removes files from the configured artifacts directory using glob patterns. + Defaults target NuGet outputs (*.nupkg, *.snupkg). Typically placed at the + end of the Release stage after DotNetCreateArchive or publish plugins. #> if (-not (Get-Command Import-PluginDependency -ErrorAction SilentlyContinue)) { - $pluginSupportModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" + $srcDir = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent + $pluginSupportModulePath = Join-Path $srcDir "modules/Engine/PluginSupport.psm1" if (Test-Path $pluginSupportModulePath -PathType Leaf) { Import-Module $pluginSupportModulePath -Force -Global -ErrorAction Stop } @@ -75,7 +76,7 @@ function Invoke-Plugin { $excludePatterns = Get-ExcludePatternsInternal -ConfiguredPatterns $pluginSettings.excludePatterns if ([string]::IsNullOrWhiteSpace($artifactsDirectory)) { - throw "CleanupArtifacts plugin requires an artifacts directory in the shared context." + throw "DotNetCleanupArtifacts plugin requires an artifacts directory in the shared context." } if (-not (Test-Path $artifactsDirectory -PathType Container)) { diff --git a/utils/Release-Package/CorePlugins/CreateArchive.psm1 b/utils/src/plugins/DotNet/DotNetCreateArchive.psm1 similarity index 84% rename from utils/Release-Package/CorePlugins/CreateArchive.psm1 rename to utils/src/plugins/DotNet/DotNetCreateArchive.psm1 index 2a4e901..92b34bd 100644 --- a/utils/Release-Package/CorePlugins/CreateArchive.psm1 +++ b/utils/src/plugins/DotNet/DotNetCreateArchive.psm1 @@ -3,16 +3,17 @@ <# .SYNOPSIS - Creates a release zip from prepared build artifacts. + .NET release archive plugin — zip from NuGet pack/publish artifacts. .DESCRIPTION - This plugin compresses the release artifact inputs prepared by an earlier - producer plugin (for example DotNetPack or DotNetPublish) into a zip file + This plugin compresses .NET release artifact inputs prepared by an earlier + DotNet plugin (DotNetPack or DotNetPublish) into a zip file and exposes the resulting release assets for later publisher plugins. #> if (-not (Get-Command Import-PluginDependency -ErrorAction SilentlyContinue)) { - $pluginSupportModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" + $srcDir = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent + $pluginSupportModulePath = Join-Path $srcDir "modules/Engine/PluginSupport.psm1" if (Test-Path $pluginSupportModulePath -PathType Leaf) { Import-Module $pluginSupportModulePath -Force -Global -ErrorAction Stop } @@ -43,11 +44,11 @@ function Invoke-Plugin { } if ($archiveInputs.Count -eq 0) { - throw "CreateArchive plugin requires prepared artifacts. Run a producer plugin (for example DotNetPack or DotNetPublish) first." + throw "DotNetCreateArchive plugin requires prepared artifacts. Run DotNetPack or DotNetPublish first." } if ([string]::IsNullOrWhiteSpace($artifactsDirectory)) { - throw "CreateArchive plugin requires an artifacts directory in the shared context." + throw "DotNetCreateArchive plugin requires an artifacts directory in the shared context." } if (-not (Test-Path $artifactsDirectory -PathType Container)) { diff --git a/utils/Release-Package/CorePlugins/DockerPush.psm1 b/utils/src/plugins/DotNet/DotNetDockerPush.psm1 similarity index 91% rename from utils/Release-Package/CorePlugins/DockerPush.psm1 rename to utils/src/plugins/DotNet/DotNetDockerPush.psm1 index ca7f44a..6e6855a 100644 --- a/utils/Release-Package/CorePlugins/DockerPush.psm1 +++ b/utils/src/plugins/DotNet/DotNetDockerPush.psm1 @@ -3,7 +3,7 @@ <# .SYNOPSIS - Build and push Docker images to a container registry. + .NET Docker publish plugin — build and push container images for .NET apps. .DESCRIPTION Logs in with credentials from a Base64-encoded username:password environment variable, @@ -15,7 +15,8 @@ #> if (-not (Get-Command Import-PluginDependency -ErrorAction SilentlyContinue)) { - $pluginSupportModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" + $srcDir = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent + $pluginSupportModulePath = Join-Path $srcDir "modules/Engine/PluginSupport.psm1" if (Test-Path $pluginSupportModulePath -PathType Leaf) { Import-Module $pluginSupportModulePath -Force -Global -ErrorAction Stop } @@ -83,23 +84,23 @@ function Invoke-Plugin { Assert-Command docker if ([string]::IsNullOrWhiteSpace($pluginSettings.registryUrl)) { - throw "DockerPush plugin requires 'registryUrl' (registry hostname, no scheme)." + throw "DotNetDockerPush plugin requires 'registryUrl' (registry hostname, no scheme)." } if ([string]::IsNullOrWhiteSpace($pluginSettings.credentialsEnvVar)) { - throw "DockerPush plugin requires 'credentialsEnvVar' (name of env var holding base64 username:password)." + throw "DotNetDockerPush plugin requires 'credentialsEnvVar' (name of env var holding base64 username:password)." } if ([string]::IsNullOrWhiteSpace($pluginSettings.projectName)) { - throw "DockerPush plugin requires 'projectName' (image path segment after registry)." + throw "DotNetDockerPush plugin requires 'projectName' (image path segment after registry)." } if ([string]::IsNullOrWhiteSpace($pluginSettings.contextPath)) { - throw "DockerPush plugin requires 'contextPath' (Docker build context, relative to Release-Package folder)." + throw "DotNetDockerPush plugin requires 'contextPath' (Docker build context, relative to engines/release folder)." } if (-not $pluginSettings.images -or @($pluginSettings.images).Count -eq 0) { - throw "DockerPush plugin requires a non-empty 'images' array with 'service' and 'dockerfile' per entry." + throw "DotNetDockerPush plugin requires a non-empty 'images' array with 'service' and 'dockerfile' per entry." } $scriptDir = $shared.scriptDir @@ -119,7 +120,7 @@ function Invoke-Plugin { $bareVersion = ([string]$shared.tag).Trim() -replace '^[vV]', '' } if ([string]::IsNullOrWhiteSpace($bareVersion)) { - throw "DockerPush: could not derive version tag (need shared.version from DotNetReleaseVersion or shared.tag)." + throw "DotNetDockerPush: could not derive version tag (need shared.version from DotNetReleaseVersion or shared.tag)." } $imageTags = New-Object System.Collections.Generic.List[string] diff --git a/utils/Release-Package/CorePlugins/HelmPush.psm1 b/utils/src/plugins/DotNet/DotNetHelmPush.psm1 similarity index 92% rename from utils/Release-Package/CorePlugins/HelmPush.psm1 rename to utils/src/plugins/DotNet/DotNetHelmPush.psm1 index 02383e1..44532f0 100644 --- a/utils/Release-Package/CorePlugins/HelmPush.psm1 +++ b/utils/src/plugins/DotNet/DotNetHelmPush.psm1 @@ -3,7 +3,7 @@ <# .SYNOPSIS - Package a Helm chart and push it to an OCI registry. + .NET Helm publish plugin — package and push charts versioned from DotNetReleaseVersion. .DESCRIPTION The chart in the repo should keep placeholder version and appVersion (e.g. 0.0.0); this plugin @@ -16,7 +16,8 @@ #> if (-not (Get-Command Import-PluginDependency -ErrorAction SilentlyContinue)) { - $pluginSupportModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" + $srcDir = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent + $pluginSupportModulePath = Join-Path $srcDir "modules/Engine/PluginSupport.psm1" if (Test-Path $pluginSupportModulePath -PathType Leaf) { Import-Module $pluginSupportModulePath -Force -Global -ErrorAction Stop } @@ -65,15 +66,15 @@ function Invoke-Plugin { $pushLatest = if ($null -ne $pluginSettings.pushLatest) { [bool]$pluginSettings.pushLatest } else { $false } if ([string]::IsNullOrWhiteSpace($pluginSettings.chartPath)) { - throw "HelmPush plugin requires 'chartPath' (chart directory, relative to Release-Package folder)." + throw "DotNetHelmPush plugin requires 'chartPath' (chart directory, relative to engines/release folder)." } if ([string]::IsNullOrWhiteSpace($pluginSettings.ociRepository)) { - throw "HelmPush plugin requires 'ociRepository' (e.g. oci://cr.maks-it.com/charts)." + throw "DotNetHelmPush plugin requires 'ociRepository' (e.g. oci://cr.maks-it.com/charts)." } if ([string]::IsNullOrWhiteSpace($pluginSettings.credentialsEnvVar)) { - throw "HelmPush plugin requires 'credentialsEnvVar' (name of env var holding base64 username:password)." + throw "DotNetHelmPush plugin requires 'credentialsEnvVar' (name of env var holding base64 username:password)." } $scriptDir = $shared.ScriptDir diff --git a/utils/Release-Package/CorePlugins/DotNetNuGet.psm1 b/utils/src/plugins/DotNet/DotNetNuGet.psm1 similarity index 92% rename from utils/Release-Package/CorePlugins/DotNetNuGet.psm1 rename to utils/src/plugins/DotNet/DotNetNuGet.psm1 index 349fd95..ecb2eb0 100644 --- a/utils/Release-Package/CorePlugins/DotNetNuGet.psm1 +++ b/utils/src/plugins/DotNet/DotNetNuGet.psm1 @@ -11,7 +11,8 @@ #> if (-not (Get-Command Import-PluginDependency -ErrorAction SilentlyContinue)) { - $pluginSupportModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" + $srcDir = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent + $pluginSupportModulePath = Join-Path $srcDir "modules/Engine/PluginSupport.psm1" if (Test-Path $pluginSupportModulePath -PathType Leaf) { Import-Module $pluginSupportModulePath -Force -Global -ErrorAction Stop } @@ -38,7 +39,7 @@ function Invoke-Plugin { } if ([string]::IsNullOrWhiteSpace($nugetApiKeyEnvVar)) { - throw "DotNetNuGet plugin requires 'nugetApiKey' in scriptsettings.json." + throw "DotNetNuGet plugin requires 'nugetApiKey' in scriptSettings.json." } $nugetApiKey = [System.Environment]::GetEnvironmentVariable($nugetApiKeyEnvVar) diff --git a/utils/Release-Package/CorePlugins/DotNetPack.psm1 b/utils/src/plugins/DotNet/DotNetPack.psm1 similarity index 95% rename from utils/Release-Package/CorePlugins/DotNetPack.psm1 rename to utils/src/plugins/DotNet/DotNetPack.psm1 index 4334e1f..bffc191 100644 --- a/utils/Release-Package/CorePlugins/DotNetPack.psm1 +++ b/utils/src/plugins/DotNet/DotNetPack.psm1 @@ -13,7 +13,8 @@ #> if (-not (Get-Command Import-PluginDependency -ErrorAction SilentlyContinue)) { - $pluginSupportModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" + $srcDir = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent + $pluginSupportModulePath = Join-Path $srcDir "modules/Engine/PluginSupport.psm1" if (Test-Path $pluginSupportModulePath -PathType Leaf) { # Load this globally only as a fallback. Re-importing PluginSupport in its own execution path # can invalidate commands already resolved by the release engine. @@ -29,7 +30,7 @@ function Invoke-Plugin { Import-PluginDependency -ModuleName "Logging" -RequiredCommand "Write-Log" Import-PluginDependency -ModuleName "ScriptConfig" -RequiredCommand "Assert-Command" - Import-PluginDependency -ModuleName "ReleaseContext" -RequiredCommand "Resolve-RelativePaths" + Import-PluginDependency -ModuleName "EngineContext" -RequiredCommand "Resolve-RelativePaths" $sharedSettings = $Settings.context $scriptDir = $sharedSettings.scriptDir diff --git a/utils/Release-Package/CorePlugins/DotNetPublish.psm1 b/utils/src/plugins/DotNet/DotNetPublish.psm1 similarity index 94% rename from utils/Release-Package/CorePlugins/DotNetPublish.psm1 rename to utils/src/plugins/DotNet/DotNetPublish.psm1 index e5e8235..84c4ec2 100644 --- a/utils/Release-Package/CorePlugins/DotNetPublish.psm1 +++ b/utils/src/plugins/DotNet/DotNetPublish.psm1 @@ -12,7 +12,8 @@ #> if (-not (Get-Command Import-PluginDependency -ErrorAction SilentlyContinue)) { - $pluginSupportModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" + $srcDir = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent + $pluginSupportModulePath = Join-Path $srcDir "modules/Engine/PluginSupport.psm1" if (Test-Path $pluginSupportModulePath -PathType Leaf) { Import-Module $pluginSupportModulePath -Force -Global -ErrorAction Stop } diff --git a/utils/Release-Package/CorePlugins/DotNetReleaseVersion.psm1 b/utils/src/plugins/DotNet/DotNetReleaseVersion.psm1 similarity index 77% rename from utils/Release-Package/CorePlugins/DotNetReleaseVersion.psm1 rename to utils/src/plugins/DotNet/DotNetReleaseVersion.psm1 index 32d7ffb..66ac1b6 100644 --- a/utils/Release-Package/CorePlugins/DotNetReleaseVersion.psm1 +++ b/utils/src/plugins/DotNet/DotNetReleaseVersion.psm1 @@ -7,11 +7,12 @@ .DESCRIPTION Dedicated version-loading plugin. It reads .csproj version via - ReleaseContext helpers and writes Version into the shared runtime context. + EngineContext helpers and writes Version into the shared runtime context. #> if (-not (Get-Command Import-PluginDependency -ErrorAction SilentlyContinue)) { - $pluginSupportModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" + $srcDir = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent + $pluginSupportModulePath = Join-Path $srcDir "modules/Engine/PluginSupport.psm1" if (Test-Path $pluginSupportModulePath -PathType Leaf) { Import-Module $pluginSupportModulePath -Force -Global -ErrorAction Stop } @@ -24,7 +25,7 @@ function Invoke-Plugin { ) Import-PluginDependency -ModuleName "Logging" -RequiredCommand "Write-Log" - Import-PluginDependency -ModuleName "ReleaseContext" -RequiredCommand "Resolve-DotNetReleaseVersion" + Import-PluginDependency -ModuleName "EngineContext" -RequiredCommand "Resolve-DotNetReleaseVersion" $shared = $Settings.context $resolved = Resolve-DotNetReleaseVersion -Plugins @($Settings) -ScriptDir $shared.scriptDir diff --git a/utils/Release-Package/CorePlugins/DotNetTest.psm1 b/utils/src/plugins/DotNet/DotNetTest.psm1 similarity index 96% rename from utils/Release-Package/CorePlugins/DotNetTest.psm1 rename to utils/src/plugins/DotNet/DotNetTest.psm1 index dba703e..188a825 100644 --- a/utils/Release-Package/CorePlugins/DotNetTest.psm1 +++ b/utils/src/plugins/DotNet/DotNetTest.psm1 @@ -15,7 +15,8 @@ #> if (-not (Get-Command Import-PluginDependency -ErrorAction SilentlyContinue)) { - $pluginSupportModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" + $srcDir = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent + $pluginSupportModulePath = Join-Path $srcDir "modules/Engine/PluginSupport.psm1" if (Test-Path $pluginSupportModulePath -PathType Leaf) { # Same fallback pattern as the other plugins: use the existing shared module if it is already loaded. Import-Module $pluginSupportModulePath -Force -Global -ErrorAction Stop @@ -47,7 +48,7 @@ function Invoke-Plugin { $testProjectPaths.Add([System.IO.Path]::GetFullPath((Join-Path $scriptDir $pluginSettings.project))) } if ($testProjectPaths.Count -eq 0) { - throw "DotNetTest plugin requires 'project' or 'projects' in scriptsettings.json." + throw "DotNetTest plugin requires 'project' or 'projects' in scriptSettings.json." } $testResultsDir = $null diff --git a/utils/Release-Package/CorePlugins/NpmBuild.psm1 b/utils/src/plugins/Npm/NpmBuild.psm1 similarity index 91% rename from utils/Release-Package/CorePlugins/NpmBuild.psm1 rename to utils/src/plugins/Npm/NpmBuild.psm1 index aeec2d0..7c43f52 100644 --- a/utils/Release-Package/CorePlugins/NpmBuild.psm1 +++ b/utils/src/plugins/Npm/NpmBuild.psm1 @@ -12,7 +12,8 @@ #> if (-not (Get-Command Import-PluginDependency -ErrorAction SilentlyContinue)) { - $pluginSupportModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" + $srcDir = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent + $pluginSupportModulePath = Join-Path $srcDir "modules/Engine/PluginSupport.psm1" if (Test-Path $pluginSupportModulePath -PathType Leaf) { Import-Module $pluginSupportModulePath -Force -Global -ErrorAction Stop } @@ -26,7 +27,7 @@ function Invoke-Plugin { Import-PluginDependency -ModuleName "Logging" -RequiredCommand "Write-Log" Import-PluginDependency -ModuleName "ScriptConfig" -RequiredCommand "Assert-Command" - Import-PluginDependency -ModuleName "ReleaseContext" -RequiredCommand "Resolve-RelativePaths" + Import-PluginDependency -ModuleName "EngineContext" -RequiredCommand "Resolve-RelativePaths" $pluginSettings = $Settings $shared = $Settings.context diff --git a/utils/Run-Tests/CorePlugins/NpmJestTest.psm1 b/utils/src/plugins/Npm/NpmJestTest.psm1 similarity index 91% rename from utils/Run-Tests/CorePlugins/NpmJestTest.psm1 rename to utils/src/plugins/Npm/NpmJestTest.psm1 index 3566e56..82803c7 100644 --- a/utils/Run-Tests/CorePlugins/NpmJestTest.psm1 +++ b/utils/src/plugins/Npm/NpmJestTest.psm1 @@ -3,7 +3,7 @@ <# .SYNOPSIS - npm/Jest test plugin for the Run-Tests engine. + npm/Jest test plugin for the test engine. .DESCRIPTION Runs Jest with coverage via TestRunner.Invoke-NpmJestTestsWithCoverage and publishes @@ -11,7 +11,8 @@ #> if (-not (Get-Command Import-PluginDependency -ErrorAction SilentlyContinue)) { - $pluginSupportModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" + $srcDir = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent + $pluginSupportModulePath = Join-Path $srcDir "modules/Engine/PluginSupport.psm1" if (Test-Path $pluginSupportModulePath -PathType Leaf) { Import-Module $pluginSupportModulePath -Force -Global -ErrorAction Stop } @@ -26,7 +27,7 @@ function Invoke-Plugin { Import-PluginDependency -ModuleName "Logging" -RequiredCommand "Write-Log" Import-PluginDependency -ModuleName "TestRunner" -RequiredCommand "Invoke-NpmJestTestsWithCoverage" Import-PluginDependency -ModuleName "ScriptConfig" -RequiredCommand "Assert-Command" - Import-PluginDependency -ModuleName "ReleaseContext" -RequiredCommand "Resolve-RelativePaths" + Import-PluginDependency -ModuleName "EngineContext" -RequiredCommand "Resolve-RelativePaths" $pluginSettings = $Settings $sharedSettings = $Settings.context @@ -35,7 +36,7 @@ function Invoke-Plugin { Assert-Command npm if (-not $pluginSettings.workspaceRoot) { - throw "NpmJestTest plugin requires 'workspaceRoot' in scriptsettings.json." + throw "NpmJestTest plugin requires 'workspaceRoot' in scriptSettings.json." } $workspaceRoots = @(Resolve-RelativePaths -Value $pluginSettings.workspaceRoot -BasePath $scriptDir) diff --git a/utils/Release-Package/CorePlugins/NpmPublish.psm1 b/utils/src/plugins/Npm/NpmPublish.psm1 similarity index 92% rename from utils/Release-Package/CorePlugins/NpmPublish.psm1 rename to utils/src/plugins/Npm/NpmPublish.psm1 index 1e996b4..7ff8259 100644 --- a/utils/Release-Package/CorePlugins/NpmPublish.psm1 +++ b/utils/src/plugins/Npm/NpmPublish.psm1 @@ -12,7 +12,8 @@ #> if (-not (Get-Command Import-PluginDependency -ErrorAction SilentlyContinue)) { - $pluginSupportModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" + $srcDir = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent + $pluginSupportModulePath = Join-Path $srcDir "modules/Engine/PluginSupport.psm1" if (Test-Path $pluginSupportModulePath -PathType Leaf) { Import-Module $pluginSupportModulePath -Force -Global -ErrorAction Stop } @@ -26,7 +27,7 @@ function Invoke-Plugin { Import-PluginDependency -ModuleName "Logging" -RequiredCommand "Write-Log" Import-PluginDependency -ModuleName "ScriptConfig" -RequiredCommand "Assert-Command" - Import-PluginDependency -ModuleName "ReleaseContext" -RequiredCommand "Resolve-RelativePaths" + Import-PluginDependency -ModuleName "EngineContext" -RequiredCommand "Resolve-RelativePaths" $pluginSettings = $Settings $shared = $Settings.context @@ -35,7 +36,7 @@ function Invoke-Plugin { $npmApiKeyEnvVar = $pluginSettings.npmApiKey if ([string]::IsNullOrWhiteSpace($npmApiKeyEnvVar)) { - throw "NpmPublish plugin requires 'npmApiKey' in scriptsettings.json (environment variable name)." + throw "NpmPublish plugin requires 'npmApiKey' in scriptSettings.json (environment variable name)." } $npmApiKey = [System.Environment]::GetEnvironmentVariable($npmApiKeyEnvVar) diff --git a/utils/Release-Package/CorePlugins/NpmReleaseVersion.psm1 b/utils/src/plugins/Npm/NpmReleaseVersion.psm1 similarity index 92% rename from utils/Release-Package/CorePlugins/NpmReleaseVersion.psm1 rename to utils/src/plugins/Npm/NpmReleaseVersion.psm1 index 2045209..3020c78 100644 --- a/utils/Release-Package/CorePlugins/NpmReleaseVersion.psm1 +++ b/utils/src/plugins/Npm/NpmReleaseVersion.psm1 @@ -12,7 +12,8 @@ #> if (-not (Get-Command Import-PluginDependency -ErrorAction SilentlyContinue)) { - $pluginSupportModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" + $srcDir = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent + $pluginSupportModulePath = Join-Path $srcDir "modules/Engine/PluginSupport.psm1" if (Test-Path $pluginSupportModulePath -PathType Leaf) { Import-Module $pluginSupportModulePath -Force -Global -ErrorAction Stop } @@ -63,14 +64,14 @@ function Invoke-Plugin { ) Import-PluginDependency -ModuleName "Logging" -RequiredCommand "Write-Log" - Import-PluginDependency -ModuleName "ReleaseContext" -RequiredCommand "Resolve-RelativePaths" + Import-PluginDependency -ModuleName "EngineContext" -RequiredCommand "Resolve-RelativePaths" $pluginSettings = $Settings $shared = $Settings.context $packageJsonPaths = @(Resolve-RelativePaths -Value $pluginSettings.packageJsonPath -BasePath $shared.scriptDir) if ($packageJsonPaths.Count -eq 0) { - throw "NpmReleaseVersion plugin requires 'packageJsonPath' in scriptsettings.json." + throw "NpmReleaseVersion plugin requires 'packageJsonPath' in scriptSettings.json." } $packageJsonPath = $packageJsonPaths[0] diff --git a/utils/Run-Tests/CorePlugins/CoverageBadges.psm1 b/utils/src/plugins/Platform/CoverageBadges.psm1 similarity index 94% rename from utils/Run-Tests/CorePlugins/CoverageBadges.psm1 rename to utils/src/plugins/Platform/CoverageBadges.psm1 index 398c295..36ba26a 100644 --- a/utils/Run-Tests/CorePlugins/CoverageBadges.psm1 +++ b/utils/src/plugins/Platform/CoverageBadges.psm1 @@ -3,14 +3,15 @@ <# .SYNOPSIS - Coverage badge plugin for the Run-Tests engine. + Coverage badge plugin for the test engine. .DESCRIPTION Reads line/branch/method coverage from shared engine context and writes SVG badges. #> if (-not (Get-Command Import-PluginDependency -ErrorAction SilentlyContinue)) { - $pluginSupportModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" + $srcDir = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent + $pluginSupportModulePath = Join-Path $srcDir "modules/Engine/PluginSupport.psm1" if (Test-Path $pluginSupportModulePath -PathType Leaf) { Import-Module $pluginSupportModulePath -Force -Global -ErrorAction Stop } @@ -123,7 +124,7 @@ function Invoke-Plugin { ) Import-PluginDependency -ModuleName "Logging" -RequiredCommand "Write-Log" - Import-PluginDependency -ModuleName "ReleaseContext" -RequiredCommand "Resolve-RelativePaths" + Import-PluginDependency -ModuleName "EngineContext" -RequiredCommand "Resolve-RelativePaths" $pluginSettings = $Settings $sharedSettings = $Settings.context @@ -136,7 +137,7 @@ function Invoke-Plugin { $badgesDir = $badgesDirs[0] } if ([string]::IsNullOrWhiteSpace([string]$badgesDir)) { - throw "CoverageBadges requires badgesDir in plugin settings or paths.badgesDir in scriptsettings.json." + throw "CoverageBadges requires badgesDir in plugin settings or paths.badgesDir in scriptSettings.json." } if (-not (Test-Path $badgesDir)) { diff --git a/utils/Release-Package/CorePlugins/GitHub.psm1 b/utils/src/plugins/Platform/GitHub.psm1 similarity index 97% rename from utils/Release-Package/CorePlugins/GitHub.psm1 rename to utils/src/plugins/Platform/GitHub.psm1 index 026ea22..9af816c 100644 --- a/utils/Release-Package/CorePlugins/GitHub.psm1 +++ b/utils/src/plugins/Platform/GitHub.psm1 @@ -14,7 +14,8 @@ #> if (-not (Get-Command Import-PluginDependency -ErrorAction SilentlyContinue)) { - $pluginSupportModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" + $srcDir = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent + $pluginSupportModulePath = Join-Path $srcDir "modules/Engine/PluginSupport.psm1" if (Test-Path $pluginSupportModulePath -PathType Leaf) { Import-Module $pluginSupportModulePath -Force -Global -ErrorAction Stop } @@ -110,7 +111,7 @@ function Invoke-Plugin { Assert-Command gh if ([string]::IsNullOrWhiteSpace($githubTokenEnvVar)) { - throw "GitHub plugin requires 'githubToken' in scriptsettings.json." + throw "GitHub plugin requires 'githubToken' in scriptSettings.json." } $githubToken = [System.Environment]::GetEnvironmentVariable($githubTokenEnvVar) @@ -119,7 +120,7 @@ function Invoke-Plugin { } if ([string]::IsNullOrWhiteSpace($releaseNotesFileSetting)) { - throw "GitHub plugin requires 'releaseNotesFile' in scriptsettings.json." + throw "GitHub plugin requires 'releaseNotesFile' in scriptSettings.json." } $releaseNotesFile = [System.IO.Path]::GetFullPath((Join-Path $scriptDir $releaseNotesFileSetting)) diff --git a/utils/Release-Package/CorePlugins/QualityGate.psm1 b/utils/src/plugins/Platform/QualityGate.psm1 similarity index 94% rename from utils/Release-Package/CorePlugins/QualityGate.psm1 rename to utils/src/plugins/Platform/QualityGate.psm1 index 830c08b..da18d38 100644 --- a/utils/Release-Package/CorePlugins/QualityGate.psm1 +++ b/utils/src/plugins/Platform/QualityGate.psm1 @@ -19,11 +19,12 @@ When scanVulnerabilities is true, runs dotnet list package --vulnerable on projectFiles. - Use stageLabel "qualityGate" in scriptsettings.json; plugin module: CorePlugins/QualityGate.psm1 (`"name": "QualityGate"`). + Use stageLabel "qualityGate" in scriptSettings.json; plugin: plugins/Platform/QualityGate.psm1 (`"name": "QualityGate"`). #> if (-not (Get-Command Import-PluginDependency -ErrorAction SilentlyContinue)) { - $pluginSupportModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" + $srcDir = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent + $pluginSupportModulePath = Join-Path $srcDir "modules/Engine/PluginSupport.psm1" if (Test-Path $pluginSupportModulePath -PathType Leaf) { Import-Module $pluginSupportModulePath -Force -Global -ErrorAction Stop } @@ -91,7 +92,7 @@ function Invoke-Plugin { Import-PluginDependency -ModuleName "Logging" -RequiredCommand "Write-Log" Import-PluginDependency -ModuleName "ScriptConfig" -RequiredCommand "Assert-Command" - Import-PluginDependency -ModuleName "ReleaseContext" -RequiredCommand "Resolve-RelativePaths" + Import-PluginDependency -ModuleName "EngineContext" -RequiredCommand "Resolve-RelativePaths" $pluginSettings = $Settings $sharedSettings = $Settings.context diff --git a/utils/Release-Package/CorePlugins/ReleasePublishGuard.psm1 b/utils/src/plugins/Platform/ReleasePublishGuard.psm1 similarity index 93% rename from utils/Release-Package/CorePlugins/ReleasePublishGuard.psm1 rename to utils/src/plugins/Platform/ReleasePublishGuard.psm1 index 09be291..adfb262 100644 --- a/utils/Release-Package/CorePlugins/ReleasePublishGuard.psm1 +++ b/utils/src/plugins/Platform/ReleasePublishGuard.psm1 @@ -3,10 +3,10 @@ <# .SYNOPSIS - Central gate for publish-stage plugins (Docker, Helm, GitHub, NuGet). + Central gate for publish-stage plugins (DotNetDockerPush, DotNetHelmPush, GitHub, DotNetNuGet, NpmPublish). .DESCRIPTION - Place this plugin immediately before any publish plugins in scriptsettings.json. It sets + Place this plugin immediately before any publish plugins in scriptSettings.json. It sets shared context skipPublishPlugins to false when all configured requirements pass, or true when they do not (whenRequirementsNotMet: skip). Publish plugins no longer use per-plugin branch lists; put allowed branches here instead. @@ -19,7 +19,8 @@ #> if (-not (Get-Command Import-PluginDependency -ErrorAction SilentlyContinue)) { - $pluginSupportModulePath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" + $srcDir = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent + $pluginSupportModulePath = Join-Path $srcDir "modules/Engine/PluginSupport.psm1" if (Test-Path $pluginSupportModulePath -PathType Leaf) { Import-Module $pluginSupportModulePath -Force -Global -ErrorAction Stop } @@ -65,8 +66,7 @@ function Invoke-Plugin { ) Import-PluginDependency -ModuleName "Logging" -RequiredCommand "Write-Log" - $pluginSupportPath = Join-Path (Split-Path $PSScriptRoot -Parent) "PluginSupport.psm1" - Import-Module $pluginSupportPath -Force -Global -ErrorAction Stop + Import-PluginDependency -ModuleName "PluginSupport" -RequiredCommand "Get-PluginBranches" Import-PluginDependency -ModuleName "GitTools" -RequiredCommand "Get-GitStatusShort" Import-PluginDependency -ModuleName "GitTools" -RequiredCommand "Test-RemoteTagExists" diff --git a/utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 b/utils/src/tools/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 similarity index 93% rename from utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 rename to utils/src/tools/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 index d338a36..c144f6a 100644 --- a/utils/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 +++ b/utils/src/tools/Force-AmendTaggedCommit/Force-AmendTaggedCommit.ps1 @@ -13,7 +13,7 @@ 4. Deletes and recreates the tag on the amended commit 5. Force pushes the branch and tag to remote - All configuration is in scriptsettings.json. + All configuration is in scriptSettings.json. .PARAMETER DryRun If specified, shows what would be done without making changes. @@ -25,7 +25,7 @@ pwsh -File .\Force-AmendTaggedCommit.ps1 -DryRun .NOTES - CONFIGURATION (scriptsettings.json): + CONFIGURATION (scriptSettings.json): - git.remote: Remote name to push to (default: "origin") - git.confirmBeforeAmend: Prompt before amending (default: true) - git.confirmWhenNoChanges: Prompt if no pending changes (default: true) @@ -37,27 +37,26 @@ param( [switch]$DryRun ) -# Get the directory of the current script (for loading settings and relative paths) $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path -$utilsDir = Split-Path $scriptDir -Parent +$srcDir = Split-Path (Split-Path $scriptDir -Parent) -Parent +$modulesDir = Join-Path $srcDir 'modules' #region Import Modules -# Import shared ScriptConfig module (settings loading + dependency checks) -$scriptConfigModulePath = Join-Path $utilsDir "ScriptConfig.psm1" +$scriptConfigModulePath = Join-Path $modulesDir "ScriptConfig.psm1" if (-not (Test-Path $scriptConfigModulePath)) { Write-Error "ScriptConfig module not found at: $scriptConfigModulePath" exit 1 } # Import shared GitTools module (git operations used by this script) -$gitToolsModulePath = Join-Path $utilsDir "GitTools.psm1" +$gitToolsModulePath = Join-Path $modulesDir "GitTools.psm1" if (-not (Test-Path $gitToolsModulePath)) { Write-Error "GitTools module not found at: $gitToolsModulePath" exit 1 } -$loggingModulePath = Join-Path $utilsDir "Logging.psm1" +$loggingModulePath = Join-Path $modulesDir "Logging.psm1" if (-not (Test-Path $loggingModulePath)) { Write-Error "Logging module not found at: $loggingModulePath" exit 1 diff --git a/utils/Force-AmendTaggedCommit/scriptsettings.json b/utils/src/tools/Force-AmendTaggedCommit/scriptSettings.json similarity index 100% rename from utils/Force-AmendTaggedCommit/scriptsettings.json rename to utils/src/tools/Force-AmendTaggedCommit/scriptSettings.json diff --git a/utils/Update-RepoUtils/Update-RepoUtils.ps1 b/utils/src/tools/Update-RepoUtils/Update-RepoUtils.ps1 similarity index 94% rename from utils/Update-RepoUtils/Update-RepoUtils.ps1 rename to utils/src/tools/Update-RepoUtils/Update-RepoUtils.ps1 index 410d078..80082c3 100644 --- a/utils/Update-RepoUtils/Update-RepoUtils.ps1 +++ b/utils/src/tools/Update-RepoUtils/Update-RepoUtils.ps1 @@ -8,16 +8,16 @@ .DESCRIPTION This script clones the configured repository into a temporary directory, refreshes the parent directory of this script, preserves existing - scriptsettings.json files in subfolders, and copies the cloned source + scriptSettings.json files in subfolders, and copies the cloned source contents into that parent directory. - All configuration is stored in scriptsettings.json. + All configuration is stored in scriptSettings.json. .EXAMPLE pwsh -File .\Update-RepoUtils.ps1 .NOTES - CONFIGURATION (scriptsettings.json): + CONFIGURATION (scriptSettings.json): - dryRun: If true, logs the planned update without modifying files - repository.url: Git repository to clone - repository.sourceSubdirectory: Folder copied into the target directory @@ -37,19 +37,19 @@ param( Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' -# Get the directory of the current script (for loading settings and relative paths) $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path -$utilsDir = Split-Path $scriptDir -Parent +$srcDir = Split-Path (Split-Path $scriptDir -Parent) -Parent +$modulesDir = Join-Path $srcDir 'modules' -# Refresh the parent directory that contains the shared modules and sibling tools. +# Refresh the src directory that contains modules, engines, plugins, and tools. $targetDirectory = if ([string]::IsNullOrWhiteSpace($TargetDirectoryOverride)) { - Split-Path $scriptDir -Parent + $srcDir } else { [System.IO.Path]::GetFullPath($TargetDirectoryOverride) } $currentScriptPath = [System.IO.Path]::GetFullPath($MyInvocation.MyCommand.Path) -$selfUpdateDirectory = 'Update-RepoUtils' +$selfUpdateDirectory = [System.IO.Path]::Combine('tools', 'Update-RepoUtils') function ConvertTo-NormalizedRelativePath { param( @@ -90,13 +90,13 @@ function Test-IsInRelativeDirectory { #region Import Modules -$scriptConfigModulePath = Join-Path $utilsDir "ScriptConfig.psm1" +$scriptConfigModulePath = Join-Path $modulesDir "ScriptConfig.psm1" if (-not (Test-Path $scriptConfigModulePath)) { Write-Error "ScriptConfig module not found at: $scriptConfigModulePath" exit 1 } -$loggingModulePath = Join-Path $utilsDir "Logging.psm1" +$loggingModulePath = Join-Path $modulesDir "Logging.psm1" if (-not (Test-Path $loggingModulePath)) { Write-Error "Logging module not found at: $loggingModulePath" exit 1 @@ -118,7 +118,7 @@ $settings = Get-ScriptSettings -ScriptDir $scriptDir $repositoryUrl = $settings.repository.url $dryRun = if ($null -ne $settings.dryRun) { [bool]$settings.dryRun } else { $false } $sourceSubdirectory = if ($settings.repository.sourceSubdirectory) { $settings.repository.sourceSubdirectory } else { 'src' } -$preserveFileName = if ($settings.repository.preserveFileName) { $settings.repository.preserveFileName } else { 'scriptsettings.json' } +$preserveFileName = if ($settings.repository.preserveFileName) { $settings.repository.preserveFileName } else { 'scriptSettings.json' } $cloneDepth = if ($settings.repository.cloneDepth) { [int]$settings.repository.cloneDepth } else { 1 } [string[]]$skippedRelativeDirectories = if ($settings.repository.skippedRelativeDirectories) { @( @@ -129,7 +129,10 @@ $cloneDepth = if ($settings.repository.cloneDepth) { [int]$settings.repository.c ) } else { - @([System.IO.Path]::Combine('Release-Package', 'CustomPlugins')) + @( + [System.IO.Path]::Combine('engines', 'release', 'custom'), + [System.IO.Path]::Combine('engines', 'test', 'custom') + ) } #endregion @@ -140,7 +143,7 @@ Assert-Command git Assert-Command pwsh if ([string]::IsNullOrWhiteSpace($repositoryUrl)) { - Write-Error "repository.url is required in scriptsettings.json." + Write-Error "repository.url is required in scriptSettings.json." exit 1 } diff --git a/utils/Update-RepoUtils/scriptsettings.json b/utils/src/tools/Update-RepoUtils/scriptSettings.json similarity index 76% rename from utils/Update-RepoUtils/scriptsettings.json rename to utils/src/tools/Update-RepoUtils/scriptSettings.json index ed0142c..6ad1a7f 100644 --- a/utils/Update-RepoUtils/scriptsettings.json +++ b/utils/src/tools/Update-RepoUtils/scriptSettings.json @@ -6,11 +6,11 @@ "repository": { "url": "https://github.com/MAKS-IT-COM/maksit-repoutils.git", "sourceSubdirectory": "src", - "preserveFileName": "scriptsettings.json", + "preserveFileName": "scriptSettings.json", "cloneDepth": 1, "skippedRelativeDirectories": [ - "Release-Package/CustomPlugins", - "Run-Tests/CustomPlugins" + "engines/release/custom", + "engines/test/custom" ] } }