From b3e89d46bcf28ea022213a52bce754c2b2abfc0b Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 19 Feb 2026 10:52:56 +0000 Subject: [PATCH 001/662] Bump version to 0.1.139 [skip ci] --- appinfo/info.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appinfo/info.xml b/appinfo/info.xml index be5951ae..69791f57 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -22,7 +22,7 @@ Submit a [bug report](https://github.com/OpenCatalogi/.github/issues/new/choose) Submit a [feature request](https://github.com/OpenCatalogi/.github/issues/new/choose). ]]> - 0.1.138 + 0.1.139 agpl organization Conduction From c224f89e30f541ee71e92d6869773bf1789c247a Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 6 Mar 2026 08:15:53 +0000 Subject: [PATCH 002/662] Bump version to 0.1.141 [skip ci] --- appinfo/info.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appinfo/info.xml b/appinfo/info.xml index bf641446..05c799cc 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -38,7 +38,7 @@ Free and open source under the EUPL license. Vrij en open source onder de EUPL-licentie. ]]> - 0.1.140 + 0.1.141 agpl Conduction SoftwareCatalog From c88e20537459c777505f47f1e29ed05c10567a3e Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Tue, 19 May 2026 17:15:28 +0200 Subject: [PATCH 003/662] feat(manifest-v2): migrate to universal widget manifest (#268) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(manifest-v2): migrate to universal widget manifest Phase 2 of the v2 manifest rollout (hydra ADR-036). Bumps @conduction/nextcloud-vue to ^1.0.0-beta.58 and runs manifest-migrate to convert softwarecatalog's manifest from v1 to v2. Adds the 5-kind component registry. References: procest #512, mydash #206. ``` @resolve: sentinels — carried forward verbatim per ADR-036 multi-tab settings orchestration — flattened to widgets[] slot:tab: cardComponent on type:index — migrated to card-grid widget ``` * fix(manifest-v2): forward registry prop to CnAppRoot template binding --- package-lock.json | 19 ++- package.json | 2 +- src/App.vue | 11 ++ src/main.js | 2 + src/manifest.json | 399 ++++++++++++++++++++++++++++++++++++++++------ src/registry.js | 48 ++++++ 6 files changed, 418 insertions(+), 63 deletions(-) create mode 100644 src/registry.js diff --git a/package-lock.json b/package-lock.json index 664c8c46..700dfb03 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "EUPL-1.2", "dependencies": { "@codemirror/lang-json": "^6.0.0", - "@conduction/nextcloud-vue": "^1.0.0-beta.42", + "@conduction/nextcloud-vue": "^1.0.0-beta.58", "@fortawesome/fontawesome-svg-core": "^6.5.2", "@fortawesome/free-solid-svg-icons": "^6.5.2", "@nextcloud/axios": "^2.5.0", @@ -2069,9 +2069,9 @@ } }, "node_modules/@conduction/nextcloud-vue": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-1.0.0-beta.42.tgz", - "integrity": "sha512-6ITMUXPNdfmaitFIeDMk4VjffrNKfAM5kjFUFl/XtORz4A6nD0DpEIrxdtZF1ltODlQoI+d4ADijP8pEr02U6g==", + "version": "1.0.0-beta.58", + "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-1.0.0-beta.58.tgz", + "integrity": "sha512-tFoV9jCNv+62c/MKbMgxwbOKH0pUTxnYGYW6pfjdhTLiSJts+BzGffZnK6khs6KDVbEssmAA3ntcpPp0hZqS/Q==", "license": "EUPL-1.2", "dependencies": { "@codemirror/autocomplete": "^6.0.0", @@ -2089,6 +2089,8 @@ "@nextcloud/notify_push": "^1.0.0", "@uiw/codemirror-theme-github": "^4.25.8", "@vueuse/core": "^10.0.0", + "ajv": "^8.20.0", + "ajv-formats": "^3.0.1", "apexcharts": "^4.7.0", "codemirror": "^6.0.0", "dompurify": "^3.0.0", @@ -2103,6 +2105,9 @@ "vue-color": "^2.8.2", "vue-template-compiler": "^2.7.16" }, + "bin": { + "manifest-migrate": "src/cli/manifest-migrate.js" + }, "peerDependencies": { "@nextcloud/auth": "^2.0.0 || ^3.0.0", "@nextcloud/axios": "^2.0.0", @@ -7258,7 +7263,6 @@ "version": "8.20.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -7275,7 +7279,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -11170,7 +11173,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, "license": "MIT" }, "node_modules/fast-glob": { @@ -11221,7 +11223,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "dev": true, "funding": [ { "type": "github", @@ -15240,7 +15241,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { @@ -19582,7 +19582,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" diff --git a/package.json b/package.json index cbc12944..7cc8b95d 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ ], "dependencies": { "@codemirror/lang-json": "^6.0.0", - "@conduction/nextcloud-vue": "^1.0.0-beta.42", + "@conduction/nextcloud-vue": "^1.0.0-beta.58", "@fortawesome/fontawesome-svg-core": "^6.5.2", "@fortawesome/free-solid-svg-icons": "^6.5.2", "@nextcloud/axios": "^2.5.0", diff --git a/src/App.vue b/src/App.vue index 5c414af2..d4f48161 100644 --- a/src/App.vue +++ b/src/App.vue @@ -19,6 +19,7 @@ ({}), }, + /** + * 5-kind component registry (v2 manifest pattern per hydra ADR-036). + * Each entry: { kind, component, ...kindMetadata }. Replaces + * customComponents for v2 manifests; both coexist during the + * transition window. + */ + registry: { + type: Object, + default: () => ({}), + }, /** * Page-type registry — `{ index, detail, dashboard, settings, ... }`. * Wired through to descendant `CnPageRenderer` instances via diff --git a/src/main.js b/src/main.js index fb0bc508..a45142e6 100644 --- a/src/main.js +++ b/src/main.js @@ -17,6 +17,7 @@ import pinia from './pinia.js' import App from './App.vue' import bundledManifest from './manifest.json' import customComponents from './customComponents.js' +import registry from './registry.js' import { routesFromManifest } from './router.js' // Library CSS — must be explicit import (webpack tree-shakes side-effect imports from aliased packages) @@ -77,6 +78,7 @@ tryLoadTranslations() // the values the lib resolves at render time. const pageTypesProp = { ...defaultPageTypes } const customComponentsProp = { ...customComponents } +const registryProp = { ...registry } // Resolve `@resolve:` IAppConfig sentinels in `manifest.pages[].config` // (e.g. `@resolve:voorzieningen_register`) via the lib's diff --git a/src/manifest.json b/src/manifest.json index e2a544ab..635489d6 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -1,18 +1,82 @@ { - "$schema": "https://raw.githubusercontent.com/ConductionNL/nextcloud-vue/main/src/schemas/app-manifest.schema.json", - "version": "1.0.0", - "dependencies": ["openregister"], + "$schema": "https://raw.githubusercontent.com/ConductionNL/nextcloud-vue/main/src/schemas/app-manifest-v2.schema.json", + "version": "2.0.0", + "dependencies": [ + "openregister" + ], "menu": [ - { "id": "Dashboard", "label": "Dashboard", "icon": "icon-category-dashboard", "route": "Dashboard", "order": 10 }, - { "id": "Organisaties", "label": "Organisations", "icon": "icon-group", "route": "Organisaties", "order": 20 }, - { "id": "Contactpersonen", "label": "Contacts", "icon": "icon-user", "route": "Contactpersonen", "order": 30 }, - { "id": "Contracten", "label": "Contracts", "icon": "icon-file", "route": "Contracten", "order": 40 }, - { "id": "Standaarden", "label": "Standards", "icon": "icon-checkmark", "route": "Standaarden", "order": 50 }, - { "id": "Reviews", "label": "Reviews", "icon": "icon-comment", "route": "Reviews", "order": 60 }, - { "id": "Komplianties", "label": "Compliance", "icon": "icon-checkmark", "route": "Komplianties", "order": 70 }, - { "id": "Moduleversies", "label": "Module versions", "icon": "icon-files", "route": "Moduleversies", "order": 80 }, - { "id": "Documentation", "label": "Documentation", "icon": "icon-info", "href": "https://github.com/ConductionNL/SoftwareCatalogus", "section": "settings", "order": 90 }, - { "id": "SettingsMenu", "label": "Settings", "icon": "icon-settings", "route": "Settings", "section": "settings", "order": 99 } + { + "id": "Dashboard", + "label": "Dashboard", + "icon": "icon-category-dashboard", + "route": "Dashboard", + "order": 10 + }, + { + "id": "Organisaties", + "label": "Organisations", + "icon": "icon-group", + "route": "Organisaties", + "order": 20 + }, + { + "id": "Contactpersonen", + "label": "Contacts", + "icon": "icon-user", + "route": "Contactpersonen", + "order": 30 + }, + { + "id": "Contracten", + "label": "Contracts", + "icon": "icon-file", + "route": "Contracten", + "order": 40 + }, + { + "id": "Standaarden", + "label": "Standards", + "icon": "icon-checkmark", + "route": "Standaarden", + "order": 50 + }, + { + "id": "Reviews", + "label": "Reviews", + "icon": "icon-comment", + "route": "Reviews", + "order": 60 + }, + { + "id": "Komplianties", + "label": "Compliance", + "icon": "icon-checkmark", + "route": "Komplianties", + "order": 70 + }, + { + "id": "Moduleversies", + "label": "Module versions", + "icon": "icon-files", + "route": "Moduleversies", + "order": 80 + }, + { + "id": "Documentation", + "label": "Documentation", + "icon": "icon-info", + "href": "https://github.com/ConductionNL/SoftwareCatalogus", + "section": "settings", + "order": 90 + }, + { + "id": "SettingsMenu", + "label": "Settings", + "icon": "icon-settings", + "route": "Settings", + "section": "settings", + "order": 99 + } ], "pages": [ { @@ -20,14 +84,16 @@ "route": "/", "type": "custom", "title": "Dashboard", - "component": "DashboardCustomView" + "component": "DashboardCustomView", + "_note": "TODO: manual migration required — custom page not auto-converted" }, { "id": "Organisaties", "route": "/organisaties", "type": "custom", "title": "Organisations", - "component": "OrganisatieIndexView" + "component": "OrganisatieIndexView", + "_note": "TODO: manual migration required — custom page not auto-converted" }, { "id": "Contactpersonen", @@ -37,8 +103,17 @@ "config": { "register": "@resolve:voorzieningen_register", "schema": "contactpersoon", - "columns": ["voornaam", "achternaam", "email", "telefoonnummer", "organisatie"], - "sidebar": { "enabled": true, "showMetadata": true } + "columns": [ + "voornaam", + "achternaam", + "email", + "telefoonnummer", + "organisatie" + ], + "sidebar": { + "enabled": true, + "showMetadata": true + } } }, { @@ -49,10 +124,33 @@ "config": { "register": "@resolve:voorzieningen_register", "schema": "contactpersoon", - "sidebarTabs": [ - { "id": "overview", "label": "Overview", "icon": "icon-info", "widgets": [{ "type": "data" }, { "type": "metadata" }], "order": 10 }, - { "id": "audit", "label": "Audit trail", "icon": "icon-history", "widgets": [{ "type": "audit-trail" }], "order": 90 } - ] + "sidebarProps": { + "tabs": [ + { + "id": "overview", + "label": "Overview", + "icon": "icon-info", + "widgets": [ + { + "type": "data" + }, + { + "type": "metadata" + } + ] + }, + { + "id": "audit", + "label": "Audit trail", + "icon": "icon-history", + "widgets": [ + { + "type": "audit-trail" + } + ] + } + ] + } } }, { @@ -63,8 +161,29 @@ "config": { "register": "@resolve:voorzieningen_register", "schema": "contract", - "columns": ["naam", "leverancier", { "key": "ingangsdatum", "label": "Start", "formatter": "date" }, { "key": "einddatum", "label": "End", "formatter": "date" }, { "key": "status", "label": "Status", "widget": "badge" }], - "sidebar": { "enabled": true, "showMetadata": true } + "columns": [ + "naam", + "leverancier", + { + "key": "ingangsdatum", + "label": "Start", + "formatter": "date" + }, + { + "key": "einddatum", + "label": "End", + "formatter": "date" + }, + { + "key": "status", + "label": "Status", + "widget": "badge" + } + ], + "sidebar": { + "enabled": true, + "showMetadata": true + } } }, { @@ -75,10 +194,33 @@ "config": { "register": "@resolve:voorzieningen_register", "schema": "contract", - "sidebarTabs": [ - { "id": "overview", "label": "Overview", "icon": "icon-info", "widgets": [{ "type": "data" }, { "type": "metadata" }], "order": 10 }, - { "id": "audit", "label": "Audit trail", "icon": "icon-history", "widgets": [{ "type": "audit-trail" }], "order": 90 } - ] + "sidebarProps": { + "tabs": [ + { + "id": "overview", + "label": "Overview", + "icon": "icon-info", + "widgets": [ + { + "type": "data" + }, + { + "type": "metadata" + } + ] + }, + { + "id": "audit", + "label": "Audit trail", + "icon": "icon-history", + "widgets": [ + { + "type": "audit-trail" + } + ] + } + ] + } } }, { @@ -89,8 +231,24 @@ "config": { "register": "@resolve:voorzieningen_register", "schema": "standaard", - "columns": ["naam", "versie", { "key": "categorie", "label": "Category", "widget": "badge" }, { "key": "status", "label": "Status", "widget": "badge" }], - "sidebar": { "enabled": true, "showMetadata": true } + "columns": [ + "naam", + "versie", + { + "key": "categorie", + "label": "Category", + "widget": "badge" + }, + { + "key": "status", + "label": "Status", + "widget": "badge" + } + ], + "sidebar": { + "enabled": true, + "showMetadata": true + } } }, { @@ -101,10 +259,33 @@ "config": { "register": "@resolve:voorzieningen_register", "schema": "standaard", - "sidebarTabs": [ - { "id": "overview", "label": "Overview", "icon": "icon-info", "widgets": [{ "type": "data" }, { "type": "metadata" }], "order": 10 }, - { "id": "audit", "label": "Audit trail", "icon": "icon-history", "widgets": [{ "type": "audit-trail" }], "order": 90 } - ] + "sidebarProps": { + "tabs": [ + { + "id": "overview", + "label": "Overview", + "icon": "icon-info", + "widgets": [ + { + "type": "data" + }, + { + "type": "metadata" + } + ] + }, + { + "id": "audit", + "label": "Audit trail", + "icon": "icon-history", + "widgets": [ + { + "type": "audit-trail" + } + ] + } + ] + } } }, { @@ -115,8 +296,20 @@ "config": { "register": "@resolve:voorzieningen_register", "schema": "beoordeeling", - "columns": ["titel", "auteur", "score", { "key": "datum", "label": "Date", "formatter": "date" }], - "sidebar": { "enabled": true, "showMetadata": true } + "columns": [ + "titel", + "auteur", + "score", + { + "key": "datum", + "label": "Date", + "formatter": "date" + } + ], + "sidebar": { + "enabled": true, + "showMetadata": true + } } }, { @@ -127,10 +320,33 @@ "config": { "register": "@resolve:voorzieningen_register", "schema": "beoordeeling", - "sidebarTabs": [ - { "id": "overview", "label": "Overview", "icon": "icon-info", "widgets": [{ "type": "data" }, { "type": "metadata" }], "order": 10 }, - { "id": "audit", "label": "Audit trail", "icon": "icon-history", "widgets": [{ "type": "audit-trail" }], "order": 90 } - ] + "sidebarProps": { + "tabs": [ + { + "id": "overview", + "label": "Overview", + "icon": "icon-info", + "widgets": [ + { + "type": "data" + }, + { + "type": "metadata" + } + ] + }, + { + "id": "audit", + "label": "Audit trail", + "icon": "icon-history", + "widgets": [ + { + "type": "audit-trail" + } + ] + } + ] + } } }, { @@ -141,8 +357,24 @@ "config": { "register": "@resolve:voorzieningen_register", "schema": "compliancy", - "columns": ["naam", "standaard", { "key": "status", "label": "Status", "widget": "badge" }, { "key": "datum", "label": "Date", "formatter": "date" }], - "sidebar": { "enabled": true, "showMetadata": true } + "columns": [ + "naam", + "standaard", + { + "key": "status", + "label": "Status", + "widget": "badge" + }, + { + "key": "datum", + "label": "Date", + "formatter": "date" + } + ], + "sidebar": { + "enabled": true, + "showMetadata": true + } } }, { @@ -153,10 +385,33 @@ "config": { "register": "@resolve:voorzieningen_register", "schema": "compliancy", - "sidebarTabs": [ - { "id": "overview", "label": "Overview", "icon": "icon-info", "widgets": [{ "type": "data" }, { "type": "metadata" }], "order": 10 }, - { "id": "audit", "label": "Audit trail", "icon": "icon-history", "widgets": [{ "type": "audit-trail" }], "order": 90 } - ] + "sidebarProps": { + "tabs": [ + { + "id": "overview", + "label": "Overview", + "icon": "icon-info", + "widgets": [ + { + "type": "data" + }, + { + "type": "metadata" + } + ] + }, + { + "id": "audit", + "label": "Audit trail", + "icon": "icon-history", + "widgets": [ + { + "type": "audit-trail" + } + ] + } + ] + } } }, { @@ -167,8 +422,24 @@ "config": { "register": "@resolve:voorzieningen_register", "schema": "moduleVersie", - "columns": ["versie", "module", { "key": "releaseDatum", "label": "Released", "formatter": "date" }, { "key": "status", "label": "Status", "widget": "badge" }], - "sidebar": { "enabled": true, "showMetadata": true } + "columns": [ + "versie", + "module", + { + "key": "releaseDatum", + "label": "Released", + "formatter": "date" + }, + { + "key": "status", + "label": "Status", + "widget": "badge" + } + ], + "sidebar": { + "enabled": true, + "showMetadata": true + } } }, { @@ -179,10 +450,33 @@ "config": { "register": "@resolve:voorzieningen_register", "schema": "moduleVersie", - "sidebarTabs": [ - { "id": "overview", "label": "Overview", "icon": "icon-info", "widgets": [{ "type": "data" }, { "type": "metadata" }], "order": 10 }, - { "id": "audit", "label": "Audit trail", "icon": "icon-history", "widgets": [{ "type": "audit-trail" }], "order": 90 } - ] + "sidebarProps": { + "tabs": [ + { + "id": "overview", + "label": "Overview", + "icon": "icon-info", + "widgets": [ + { + "type": "data" + }, + { + "type": "metadata" + } + ] + }, + { + "id": "audit", + "label": "Audit trail", + "icon": "icon-history", + "widgets": [ + { + "type": "audit-trail" + } + ] + } + ] + } } }, { @@ -198,7 +492,8 @@ "component": "SoftwareCatalogSettingsPage" } ] - } + }, + "widgets": [] } ] } diff --git a/src/registry.js b/src/registry.js new file mode 100644 index 00000000..f4ecf638 --- /dev/null +++ b/src/registry.js @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// Copyright (C) 2026 Conduction B.V. +// +// 5-kind component registry for v2 manifest (per hydra ADR-036). +// +// The v1 customComponents.js map is preserved alongside this file for +// backward-compat during the migration window. CnAppRoot accepts both +// props; the v2 renderer emits a one-shot deprecation warning when both +// are present and the manifest is v2. +// +// Resolution at runtime (v2 path): +// 1. Built-in widgets registry (CnWidgetGrid built-ins) +// 2. registry prop (this file) — keyed by widgetKey / target / appliesTo +// +// References: +// - hydra ADR-036 +// - nextcloud-app-template scaffold-v2 (#44) — canonical layout +// - procest #512 / mydash #206 — first reference migrations + +import OrganisatieIndexView from './views/organisaties/OrganisatieIndex.vue' +import SoftwareCatalogSettingsPage from './views/settings/SoftwareCatalogSettings.vue' +import DashboardCustomView from './views/Dashboard.vue' + +export default { + // --- Lib gap: bespoke OrganisatieCard + AddContactpersoonModal flow. --- + // Bespoke modal/dialog/deep-link wiring around CnIndexPage. The + // Organisaties manifest entry is type:'custom' with a _note pointing + // here; the page mounts this view, which internally uses CnIndexPage. + OrganisatieIndexView: { + kind: 'page', + component: OrganisatieIndexView, + }, + + // --- Lib gap: settings sub-section orchestration. --- + // Multi-tab nav + ArchiMate status polling + register selector that + // the lib's type:'settings' rich-section widgets can't express yet. + SoftwareCatalogSettingsPage: { + kind: 'page', + component: SoftwareCatalogSettingsPage, + }, + + // --- Lib gap: dashboard widget extraction pending. --- + // Preserved verbatim until extraction to a generic schema-stats widget. + DashboardCustomView: { + kind: 'page', + component: DashboardCustomView, + }, +} From 4704951454cc7ce0105df555508af512a7e54021 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Tue, 19 May 2026 19:19:39 +0200 Subject: [PATCH 004/662] fix(quality): wire registryProp to App render so no-unused-vars passes (#269) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `registryProp` was declared but never passed to `App` in the render function, causing the single ESLint `no-unused-vars` failure on the quality CI job. Adds `registry: registryProp` to the render props so the v2 component registry (registry.js) is actually forwarded to CnAppRoot — matching the pattern used by procest/mydash. Fixes https://github.com/ConductionNL/hydra/issues/307 --- src/main.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.js b/src/main.js index a45142e6..4365cf60 100644 --- a/src/main.js +++ b/src/main.js @@ -108,6 +108,7 @@ new Vue({ manifest: manifestRef.value, customComponents: customComponentsProp, pageTypes: pageTypesProp, + registry: registryProp, }, }) }, From 32070387465a8a6ac6aaf4ac56df804c87a6b03c Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Tue, 19 May 2026 23:00:09 +0200 Subject: [PATCH 005/662] fix(webpack): inject appName + appVersion via DefinePlugin (#270) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @nextcloud/vue's runtime checks for two compile-time globals (appName, appVersion) and logs a console error on every page load when they're missing — visible from mydash because it embeds the softwarecatalog ConceptOrganisaties widget. Adds the standard two-DefinePlugin pattern matching procest/pipelinq/ openconnector. --- webpack.config.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/webpack.config.js b/webpack.config.js index b9419069..4d7b217d 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,5 +1,6 @@ const path = require('path') const fs = require('fs') +const webpack = require('webpack') const webpackConfig = require('@nextcloud/webpack-vue-config') const { VueLoaderPlugin } = require('vue-loader') @@ -65,6 +66,8 @@ webpackConfig.module = { webpackConfig.plugins = [ new VueLoaderPlugin(), + new webpack.DefinePlugin({ appName: JSON.stringify(appId) }), + new webpack.DefinePlugin({ appVersion: JSON.stringify(process.env.npm_package_version) }), ] // Force @nextcloud/dialogs to resolve from this app's node_modules, From 443d6ef2bfe6bdeb8b4411139dc55169b7d56f09 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Wed, 20 May 2026 10:31:27 +0200 Subject: [PATCH 006/662] feat(manifest-v2): convert Dashboard to type:dashboard (refs #271) (#273) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drops customs from 2/15 (13%) → 1/15 (7%): * Dashboard → type:"dashboard" with a single-widget layout that references the existing DashboardCustomView via slots (matches the same pattern adopted in pipelinq #398). One residual custom remains: * Organisaties — bespoke modal + AddContactpersoonModal + deep-link wiring + cross-component store subscriptions. Will collapse to type:"index" once nc-vue gains declarative modal + deep-link wiring. Bumps @conduction/nextcloud-vue to ^1.0.0-beta.60 (default-body fallback nextcloud-vue#262 + CnDataTable getCellValue guard #263). --- package-lock.json | 2221 ++++++++++++++++++++++++++++++++++++++++++--- package.json | 13 +- src/manifest.json | 17 +- 3 files changed, 2120 insertions(+), 131 deletions(-) diff --git a/package-lock.json b/package-lock.json index 700dfb03..9e708fed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,9 @@ "version": "1.0.0", "license": "EUPL-1.2", "dependencies": { + "@babel/core": "^7.29.0", "@codemirror/lang-json": "^6.0.0", - "@conduction/nextcloud-vue": "^1.0.0-beta.58", + "@conduction/nextcloud-vue": "^1.0.0-beta.60", "@fortawesome/fontawesome-svg-core": "^6.5.2", "@fortawesome/free-solid-svg-icons": "^6.5.2", "@nextcloud/axios": "^2.5.0", @@ -24,29 +25,35 @@ "@vueuse/core": "^10.11.0", "apexcharts": "^3.50.0", "axios": "^1.7.3", + "babel-loader": "^10.1.1", "bootstrap-vue": "^2.23.1", "css-loader": "~7.1.1", "lodash": "^4.17.21", + "node-polyfill-webpack-plugin": "^3.0.0", "pinia": "^2.1.7", "remark-cli": "^12.0.1", "remark-lint-list-item-indent": "^4.0.0", "remark-preset-lint-consistent": "^6.0.0", "remark-preset-lint-recommended": "^7.0.0", + "sass": "^1.99.0", + "sass-loader": "^16.0.8", "style-loader": "~4.0.0", "vue": "^2.7.14", "vue-apexcharts": "~1.6.2", "vue-codemirror6": "^1.0.0", "vue-draggable-plus": "^0.2.0", - "vue-loader": "^15.11.1 <16.0.0", + "vue-loader": "^15.11.1", "vue-loading-overlay": "^3.4.3", "vue-material-design-icons": "^5.3.0", "vue-router": "^3.6.5", "vue-template-compiler": "^2.7.16", + "webpack": "^5.106.2", + "webpack-cli": "^7.0.2", "zod": "^3.23.8" }, "devDependencies": { "@babel/eslint-parser": "^7.28.6", - "@babel/preset-env": "^7.25.3", + "@babel/preset-env": "^7.29.5", "@cyclonedx/cyclonedx-npm": "^4.2.1", "@eslint/config-helpers": "^0.5.0", "@eslint/eslintrc": "^3.3.3", @@ -113,10 +120,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", - "dev": true, + "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==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -126,7 +132,6 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.0", @@ -215,7 +220,6 @@ "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==", - "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.28.6", @@ -289,7 +293,6 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -313,7 +316,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.28.6", @@ -327,7 +329,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.28.6", @@ -436,7 +437,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -461,7 +461,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.28.6", @@ -535,6 +534,23 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": { + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array/-/plugin-bugfix-safari-rest-destructuring-rhs-array-7.29.3.tgz", + "integrity": "sha512-SRS46DFR4HqzUzCVgi90/xMoL+zeBDBvWdKYXSEzh79kXswNFEglUpMKxR04//dPqwYXWUBJ3mpUd933ru9Kmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", @@ -1277,9 +1293,9 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.0.tgz", - "integrity": "sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==", + "version": "7.29.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.4.tgz", + "integrity": "sha512-N7QmZ0xRZfjHOfZeQLJjwgX2zS9pdGHSVl/cjSGlo4dXMqvurfxXDMKY4RqEKzPozV78VMcd0lxyG13mlbKc4w==", "dev": true, "license": "MIT", "dependencies": { @@ -1712,19 +1728,20 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.0.tgz", - "integrity": "sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==", + "version": "7.29.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.5.tgz", + "integrity": "sha512-/69t2aEzGKHD76DyLbHysF/QH2LJOB8iFnYO37unDTKBTubzcMRv0f3H5EiN1Q6ajOd/eB7dAInF0qdFVS06kA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.29.0", + "@babel/compat-data": "^7.29.3", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.3", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", @@ -1756,7 +1773,7 @@ "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.28.6", - "@babel/plugin-transform-modules-systemjs": "^7.29.0", + "@babel/plugin-transform-modules-systemjs": "^7.29.4", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.0", "@babel/plugin-transform-new-target": "^7.27.1", @@ -1824,7 +1841,6 @@ "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==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.28.6", @@ -1839,7 +1855,6 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.0", @@ -2069,9 +2084,9 @@ } }, "node_modules/@conduction/nextcloud-vue": { - "version": "1.0.0-beta.58", - "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-1.0.0-beta.58.tgz", - "integrity": "sha512-tFoV9jCNv+62c/MKbMgxwbOKH0pUTxnYGYW6pfjdhTLiSJts+BzGffZnK6khs6KDVbEssmAA3ntcpPp0hZqS/Q==", + "version": "1.0.0-beta.60", + "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-1.0.0-beta.60.tgz", + "integrity": "sha512-VZ6tyH349Oa/k+zobzA86DC7OqP6x8OkuGsXVN22wWZ0DE0584CM05te2M+3oIC9BPELFi2lt84tq0FOKf8ehw==", "license": "EUPL-1.2", "dependencies": { "@codemirror/autocomplete": "^6.0.0", @@ -2910,6 +2925,15 @@ "node": ">=10" } }, + "node_modules/@discoveryjs/json-ext": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-1.1.0.tgz", + "integrity": "sha512-Xc3VhU02wqZ1HvHRJUwL09HkZSTvidqY5Ya0NXBSYOxAp+Ln9dcJr9fySI+CkONzP3PekQo9WdzCv0PGER/mOA==", + "license": "MIT", + "engines": { + "node": ">=14.17.0" + } + }, "node_modules/@emnapi/core": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", @@ -4234,6 +4258,16 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -5578,6 +5612,333 @@ "node": ">=20.0" } }, + "node_modules/@parcel/watcher": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", + "cpu": [ + "arm" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@pinia/testing": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/@pinia/testing/-/testing-0.1.7.tgz", @@ -5855,17 +6216,26 @@ "version": "8.56.12", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz", "integrity": "sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==", - "dev": true, "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, - "node_modules/@types/esrecurse": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", - "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", "dev": true, "license": "MIT" }, @@ -5972,7 +6342,6 @@ "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, "license": "MIT" }, "node_modules/@types/json5": { @@ -7177,6 +7546,164 @@ } } }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "license": "Apache-2.0" + }, "node_modules/@yr/monotone-cubic-spline": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@yr/monotone-cubic-spline/-/monotone-cubic-spline-1.0.3.tgz", @@ -7200,6 +7727,18 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "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==", + "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", @@ -7223,6 +7762,18 @@ "acorn-walk": "^8.0.2" } }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -7534,6 +8085,36 @@ "node": ">=0.10.0" } }, + "node_modules/asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "license": "MIT" + }, + "node_modules/assert": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", + "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" + } + }, "node_modules/ast-kit": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.2.0.tgz", @@ -7609,7 +8190,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" @@ -7740,6 +8320,31 @@ "node": ">=8" } }, + "node_modules/babel-loader": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-10.1.1.tgz", + "integrity": "sha512-JwKSzk2kjIe7mgPK+/lyZ2QAaJcpahNAdM+hgR2HI8D0OJVkdj8Rl6J3kaLYki9pwF7P2iWnD8qVv80Lq1ABtg==", + "license": "MIT", + "dependencies": { + "find-up": "^5.0.0" + }, + "engines": { + "node": "^18.20.0 || ^20.10.0 || >=22.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0 || ^8.0.0-beta.1", + "@rspack/core": "^1.0.0 || ^2.0.0-0", + "webpack": ">=5.61.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", @@ -7989,7 +8594,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, "funding": [ { "type": "github", @@ -8004,14 +8608,12 @@ "url": "https://feross.org/support" } ], - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/baseline-browser-mapping": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", - "dev": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -8127,6 +8729,12 @@ "integrity": "sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w==", "license": "MIT" }, + "node_modules/bn.js": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", + "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", + "license": "MIT" + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -8193,11 +8801,138 @@ "node": ">=8" } }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "license": "MIT" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "license": "MIT", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "license": "MIT", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", + "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", + "license": "MIT", + "dependencies": { + "bn.js": "^5.2.1", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", + "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", + "license": "ISC", + "dependencies": { + "bn.js": "^5.2.2", + "browserify-rsa": "^4.1.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.6.1", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.9", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/browserify-sign/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/browserify-sign/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/browserify-sign/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/browserify-sign/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "license": "MIT", + "dependencies": { + "pako": "~1.0.5" + } + }, "node_modules/browserslist": { "version": "4.28.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", - "dev": true, "funding": [ { "type": "opencollective", @@ -8250,12 +8985,42 @@ "node-int64": "^0.4.0" } }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "license": "MIT" }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "license": "MIT" + }, "node_modules/builtin-modules": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", @@ -8269,6 +9034,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", + "license": "MIT" + }, "node_modules/builtins": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz", @@ -8358,7 +9129,6 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -8390,7 +9160,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -8479,7 +9248,6 @@ "version": "1.0.30001778", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001778.tgz", "integrity": "sha512-PN7uxFL+ExFJO61aVmP1aIEG4i9whQd4eoSCebav62UwDyp5OHh06zN4jqKSMePVgxHifCw1QJxdRkA1Pisekg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -8579,6 +9347,21 @@ "node": "*" } }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/chownr": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", @@ -8590,6 +9373,15 @@ "node": ">=18" } }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, "node_modules/ci-info": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", @@ -8606,6 +9398,20 @@ "node": ">=8" } }, + "node_modules/cipher-base": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", + "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/cjs-module-lexer": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", @@ -8643,6 +9449,32 @@ "node": ">=0.8" } }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clone-deep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -8804,6 +9636,11 @@ "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==", "license": "MIT" }, + "node_modules/console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + }, "node_modules/consolidate": { "version": "0.15.1", "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", @@ -8817,11 +9654,16 @@ "node": ">= 0.10.0" } }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", + "license": "MIT" + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, "license": "MIT" }, "node_modules/core-js": { @@ -8849,6 +9691,12 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, "node_modules/cosmiconfig": { "version": "8.3.6", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", @@ -8876,11 +9724,54 @@ } } }, - "node_modules/create-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", - "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", - "dev": true, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "license": "MIT" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -9003,6 +9894,32 @@ "node": "*" } }, + "node_modules/crypto-browserify": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", + "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", + "license": "MIT", + "dependencies": { + "browserify-cipher": "^1.0.1", + "browserify-sign": "^4.2.3", + "create-ecdh": "^4.0.4", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/css": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", @@ -9521,7 +10438,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -9539,7 +10455,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", @@ -9571,11 +10486,20 @@ "node": ">=6" } }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, "license": "Apache-2.0", "optional": true, "engines": { @@ -9615,6 +10539,23 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "license": "MIT" + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -9677,6 +10618,18 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/domain-browser": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.23.0.tgz", + "integrity": "sha512-ArzcM/II1wCCujdCNyQjXrAFwS4mrLh4C7DZWlaI8mdh7h3BfKdNd3bKXITfl2PT9FtfQqaGvhi1vPRQPimjGA==", + "license": "Artistic-2.0", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, "node_modules/domelementtype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", @@ -9800,9 +10753,29 @@ "version": "1.5.313", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.313.tgz", "integrity": "sha512-QBMrTWEf00GXZmJyx2lbYD45jpI3TUFnNIzJ5BBc8piGUDwMPa1GV6HJWTZVvY/eiN3fSopl7NRbgGp9sZ9LTA==", - "dev": true, "license": "ISC" }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "license": "MIT" + }, "node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", @@ -9884,7 +10857,6 @@ "version": "5.20.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", - "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -9917,6 +10889,18 @@ "node": ">=6" } }, + "node_modules/envinfo": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.21.0.tgz", + "integrity": "sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==", + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/err-code": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", @@ -10019,6 +11003,12 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -10081,7 +11071,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -11023,7 +12012,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -11036,7 +12024,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -11068,12 +12055,40 @@ "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==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/eventemitter3": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", "license": "MIT" }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "license": "MIT", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -11274,7 +12289,6 @@ "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 4.9.1" @@ -11383,7 +12397,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^6.0.0", @@ -11396,6 +12409,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, "node_modules/flat-cache": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", @@ -11479,7 +12501,6 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "dev": true, "license": "MIT", "dependencies": { "is-callable": "^1.2.7" @@ -11634,7 +12655,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -11644,7 +12664,6 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -11794,6 +12813,12 @@ "node": ">=10.13.0" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "license": "BSD-2-Clause" + }, "node_modules/global-modules": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", @@ -11919,7 +12944,6 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, "license": "ISC" }, "node_modules/graphemer": { @@ -12014,7 +13038,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" @@ -12066,12 +13089,35 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hash-base": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/hash-sum": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", "license": "MIT" }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -12215,6 +13261,17 @@ "node": ">=12.0.0" } }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "node_modules/hookable": { "version": "5.5.3", "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", @@ -12349,6 +13406,12 @@ "node": ">= 6" } }, + "node_modules/https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", + "license": "MIT" + }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -12377,7 +13440,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, "funding": [ { "type": "github", @@ -12392,8 +13454,7 @@ "url": "https://feross.org/support" } ], - "license": "BSD-3-Clause", - "optional": true + "license": "BSD-3-Clause" }, "node_modules/ignore": { "version": "5.3.2", @@ -12405,6 +13466,12 @@ "node": ">= 4" } }, + "node_modules/immutable": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", + "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", + "license": "MIT" + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -12446,7 +13513,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", - "dev": true, "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", @@ -12541,6 +13607,15 @@ "node": ">= 0.4" } }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/ip-address": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", @@ -12588,6 +13663,22 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -12726,7 +13817,6 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -12739,7 +13829,6 @@ "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -12850,7 +13939,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.4", @@ -12901,6 +13989,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-negative-zero": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", @@ -12981,7 +14085,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -13092,7 +14195,6 @@ "version": "1.1.15", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "dev": true, "license": "MIT", "dependencies": { "which-typed-array": "^1.1.16" @@ -13154,7 +14256,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, "license": "MIT" }, "node_modules/isexe": { @@ -13163,6 +14264,15 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", @@ -15276,7 +16386,6 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -15398,6 +16507,19 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/loader-runner": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz", + "integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==", + "license": "MIT", + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/loader-utils": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", @@ -15433,7 +16555,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^5.0.0" @@ -15521,7 +16642,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -15717,6 +16837,17 @@ "is-buffer": "~1.1.6" } }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, "node_modules/mdast-comment-marker": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mdast-comment-marker/-/mdast-comment-marker-3.0.0.tgz", @@ -16043,7 +17174,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, "license": "MIT" }, "node_modules/merge2": { @@ -16512,6 +17642,25 @@ "node": ">=8.6" } }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "license": "MIT" + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -16557,6 +17706,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "license": "MIT" + }, "node_modules/minimatch": { "version": "10.2.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", @@ -16910,7 +18071,6 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, "license": "MIT" }, "node_modules/nested-property": { @@ -16947,6 +18107,13 @@ "node": ">=10" } }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT", + "optional": true + }, "node_modules/node-cache": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-4.2.1.tgz", @@ -17164,11 +18331,60 @@ "dev": true, "license": "MIT" }, + "node_modules/node-polyfill-webpack-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/node-polyfill-webpack-plugin/-/node-polyfill-webpack-plugin-3.0.0.tgz", + "integrity": "sha512-QpG496dDBiaelQZu9wDcVvpLbtk7h9Ctz693RaUMZBgl8DUoFToO90ZTLKq57gP7rwKqYtGbMBXkcEgLSag2jQ==", + "license": "MIT", + "dependencies": { + "assert": "^2.1.0", + "browserify-zlib": "^0.2.0", + "buffer": "^6.0.3", + "console-browserify": "^1.2.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.12.0", + "domain-browser": "^4.22.0", + "events": "^3.3.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.1", + "process": "^0.11.10", + "punycode": "^2.3.0", + "querystring-es3": "^0.2.1", + "readable-stream": "^4.4.2", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "string_decoder": "^1.3.0", + "timers-browserify": "^2.0.12", + "tty-browserify": "^0.0.1", + "type-fest": "^4.4.0", + "url": "^0.11.3", + "util": "^0.12.5", + "vm-browserify": "^1.1.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "webpack": ">=5" + } + }, + "node_modules/node-polyfill-webpack-plugin/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/node-releases": { "version": "2.0.36", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", - "dev": true, "license": "MIT" }, "node_modules/nopt": { @@ -17376,7 +18592,6 @@ "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -17385,11 +18600,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -17399,7 +18629,6 @@ "version": "4.1.7", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -17535,6 +18764,12 @@ "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==", "license": "MIT" }, + "node_modules/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", + "license": "MIT" + }, "node_modules/own-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", @@ -17557,7 +18792,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -17573,7 +18807,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^3.0.2" @@ -17631,7 +18864,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -17650,6 +18882,12 @@ "dev": true, "license": "MIT" }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -17663,6 +18901,22 @@ "node": ">=6" } }, + "node_modules/parse-asn1": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", + "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", + "license": "ISC", + "dependencies": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "pbkdf2": "^3.1.5", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/parse-entities": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", @@ -17720,11 +18974,16 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "license": "MIT" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -17768,7 +19027,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, "license": "MIT" }, "node_modules/path-posix": { @@ -17815,6 +19073,23 @@ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "license": "MIT" }, + "node_modules/pbkdf2": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", + "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", + "license": "MIT", + "dependencies": { + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "ripemd160": "^2.0.3", + "safe-buffer": "^5.2.1", + "sha.js": "^2.4.12", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/perfect-debounce": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz", @@ -17901,7 +19176,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, "license": "MIT", "dependencies": { "find-up": "^4.0.0" @@ -17914,7 +19188,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -17928,7 +19201,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -17941,7 +19213,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -17957,7 +19228,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -18010,7 +19280,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -18236,6 +19505,21 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, "node_modules/promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", @@ -18397,6 +19681,26 @@ "url": "https://github.com/sponsors/lupomontero" } }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "license": "MIT" + }, "node_modules/pump": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", @@ -18413,7 +19717,6 @@ "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" @@ -18436,6 +19739,21 @@ ], "license": "MIT" }, + "node_modules/qs": { + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/quansync": { "version": "0.2.11", "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", @@ -18452,6 +19770,14 @@ ], "license": "MIT" }, + "node_modules/querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -18515,6 +19841,25 @@ "node": ">=0.12" } }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "license": "MIT", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -18635,6 +19980,47 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "license": "MIT", + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, "node_modules/redent": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-4.0.0.tgz", @@ -19607,7 +20993,6 @@ "version": "1.22.11", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.16.1", @@ -19628,7 +21013,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" @@ -19641,7 +21025,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -19723,6 +21106,76 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/ripemd160": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", + "license": "MIT", + "dependencies": { + "hash-base": "^3.1.2", + "inherits": "^2.0.4" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ripemd160/node_modules/hash-base": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ripemd160/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/ripemd160/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/ripemd160/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/ripemd160/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/ripemd160/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/rope-sequence": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz", @@ -19814,7 +21267,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -19835,6 +21287,66 @@ "dev": true, "license": "MIT" }, + "node_modules/sass": { + "version": "1.99.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.99.0.tgz", + "integrity": "sha512-kgW13M54DUB7IsIRM5LvJkNlpH+WhMpooUcaWGFARkF1Tc82v9mIWkCbCYf+MBvpIUBSeSOTilpZjEPr2VYE6Q==", + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.1.5", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/sass-loader": { + "version": "16.0.8", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.8.tgz", + "integrity": "sha512-hcov4ZwZJIGbEuyNr9EmiTmZueyrxSToE6GOzoZnq5JM7ecRO7ttyvilPn+VmRsqiP16+VYZzVnGZj/hzZgKBA==", + "license": "MIT", + "dependencies": { + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || ^1.0.0 || ^2.0.0-0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, "node_modules/sax": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/sax/-/sax-1.5.0.tgz", @@ -19861,7 +21373,6 @@ "version": "4.3.3", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "dev": true, "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", @@ -19881,7 +21392,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -19899,7 +21409,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" @@ -19929,7 +21438,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -19939,7 +21447,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -19984,6 +21491,44 @@ "node": ">= 0.4" } }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, + "node_modules/sha.js": { + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" + }, + "bin": { + "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -20009,7 +21554,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -20029,7 +21573,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -20046,7 +21589,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -20065,7 +21607,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -20301,6 +21842,25 @@ "urix": "^0.1.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "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==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-url": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", @@ -20415,22 +21975,72 @@ "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "engines": { + "node": ">=8" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "license": "MIT", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/stream-browserify/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/stream-http": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", + "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", + "license": "MIT", + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" } }, - "node_modules/stop-iteration-iterator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", - "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", - "dev": true, + "node_modules/stream-http/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "internal-slot": "^1.1.0" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": ">= 0.4" + "node": ">= 6" } }, "node_modules/string_decoder": { @@ -21045,7 +22655,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -21185,7 +22794,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -21280,6 +22888,128 @@ "node": ">=18" } }, + "node_modules/terser": { + "version": "5.47.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.47.1.tgz", + "integrity": "sha512-tPbLXTI6ohPASb/1YViL428oEHu6/qv1OxqYnfaonVCFHqx4+wCd95pHrQWsL5X4pl90CTyW9piSAsS2L0VoMw==", + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.6.0.tgz", + "integrity": "sha512-Eum+5ajkaOhf5KbM26osvv21kLD7BaGqQ1UA4Ami4arYwylmGUQTgHFpHDdmJod1q4QXa66p0to/FBKID+J1vA==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@minify-html/node": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "@swc/css": { + "optional": true + }, + "@swc/html": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "cssnano": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "html-minifier-terser": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "postcss": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -21301,6 +23031,18 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "license": "MIT" }, + "node_modules/timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "license": "MIT", + "dependencies": { + "setimmediate": "^1.0.4" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/tinycolor2": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", @@ -21359,6 +23101,20 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/to-buffer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "license": "MIT", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/to-fast-properties": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", @@ -21750,6 +23506,12 @@ "license": "0BSD", "optional": true }, + "node_modules/tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", + "license": "MIT" + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -21804,7 +23566,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -22540,7 +24301,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "dev": true, "funding": [ { "type": "opencollective", @@ -22585,6 +24345,19 @@ "dev": true, "license": "MIT" }, + "node_modules/url": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", + "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", + "license": "MIT", + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.12.3" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/url-join": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", @@ -22604,6 +24377,25 @@ "requires-port": "^1.0.0" } }, + "node_modules/url/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "license": "MIT" + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -22806,6 +24598,12 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "license": "MIT" + }, "node_modules/vue": { "version": "2.7.16", "resolved": "https://registry.npmjs.org/vue/-/vue-2.7.16.tgz", @@ -23165,6 +24963,19 @@ "makeerror": "1.0.12" } }, + "node_modules/watchpack": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/web-namespaces": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", @@ -23237,12 +25048,162 @@ "node": ">=12" } }, + "node_modules/webpack": { + "version": "5.106.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.106.2.tgz", + "integrity": "sha512-wGN3qcrBQIFmQ/c0AiOAQBvrZ5lmY8vbbMv4Mxfgzqd/B6+9pXtLo73WuS1dSGXM5QYY3hZnIbvx+K1xxe6FyA==", + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.16.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.20.0", + "es-module-lexer": "^2.0.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "loader-runner": "^4.3.1", + "mime-db": "^1.54.0", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.17", + "watchpack": "^2.5.1", + "webpack-sources": "^3.3.4" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-7.0.2.tgz", + "integrity": "sha512-dB0R4T+C/8YuvM+fabdvil6QE44/ChDXikV5lOOkrUeCkW5hTJv2pGLE3keh+D5hjYw8icBaJkZzpFoaHV4T+g==", + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "^1.0.0", + "commander": "^14.0.3", + "cross-spawn": "^7.0.6", + "envinfo": "^7.14.0", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^6.0.1" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.101.0", + "webpack-bundle-analyzer": "^4.0.0 || ^5.0.0", + "webpack-dev-server": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/webpack-merge": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.4.1.tgz", + "integrity": "sha512-eACpxRN02yaawnt+uUNIF7Qje6A9zArxBbcAJjK1PK3S9Ycg5jIuJ8pW4q8EMnwNZCEGltcjkRx1QzOxOkKD8A==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/webpack-virtual-modules": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", "license": "MIT" }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/webpack/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/whatwg-encoding": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", @@ -23380,7 +25341,6 @@ "version": "1.1.20", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", - "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", @@ -23398,6 +25358,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "license": "MIT" + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -23596,6 +25562,15 @@ "dev": true, "license": "MIT" }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -23610,7 +25585,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, "license": "ISC" }, "node_modules/yaml": { @@ -23671,7 +25645,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" diff --git a/package.json b/package.json index 7cc8b95d..fdae7d42 100644 --- a/package.json +++ b/package.json @@ -22,8 +22,9 @@ "extends @nextcloud/browserslist-config" ], "dependencies": { + "@babel/core": "^7.29.0", "@codemirror/lang-json": "^6.0.0", - "@conduction/nextcloud-vue": "^1.0.0-beta.58", + "@conduction/nextcloud-vue": "^1.0.0-beta.60", "@fortawesome/fontawesome-svg-core": "^6.5.2", "@fortawesome/free-solid-svg-icons": "^6.5.2", "@nextcloud/axios": "^2.5.0", @@ -37,24 +38,30 @@ "@vueuse/core": "^10.11.0", "apexcharts": "^3.50.0", "axios": "^1.7.3", + "babel-loader": "^10.1.1", "bootstrap-vue": "^2.23.1", "css-loader": "~7.1.1", "lodash": "^4.17.21", + "node-polyfill-webpack-plugin": "^3.0.0", "pinia": "^2.1.7", "remark-cli": "^12.0.1", "remark-lint-list-item-indent": "^4.0.0", "remark-preset-lint-consistent": "^6.0.0", "remark-preset-lint-recommended": "^7.0.0", + "sass": "^1.99.0", + "sass-loader": "^16.0.8", "style-loader": "~4.0.0", "vue": "^2.7.14", "vue-apexcharts": "~1.6.2", "vue-codemirror6": "^1.0.0", "vue-draggable-plus": "^0.2.0", - "vue-loader": "^15.11.1 <16.0.0", + "vue-loader": "^15.11.1", "vue-loading-overlay": "^3.4.3", "vue-material-design-icons": "^5.3.0", "vue-router": "^3.6.5", "vue-template-compiler": "^2.7.16", + "webpack": "^5.106.2", + "webpack-cli": "^7.0.2", "zod": "^3.23.8" }, "overrides": { @@ -68,7 +75,7 @@ }, "devDependencies": { "@babel/eslint-parser": "^7.28.6", - "@babel/preset-env": "^7.25.3", + "@babel/preset-env": "^7.29.5", "@cyclonedx/cyclonedx-npm": "^4.2.1", "@eslint/config-helpers": "^0.5.0", "@eslint/eslintrc": "^3.3.3", diff --git a/src/manifest.json b/src/manifest.json index 635489d6..894ce7c2 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -82,10 +82,19 @@ { "id": "Dashboard", "route": "/", - "type": "custom", + "type": "dashboard", "title": "Dashboard", - "component": "DashboardCustomView", - "_note": "TODO: manual migration required — custom page not auto-converted" + "config": { + "widgets": [ + { "id": "dashboardHome", "title": "Dashboard", "type": "custom" } + ], + "layout": [ + { "id": 1, "widgetId": "dashboardHome", "gridX": 0, "gridY": 0, "gridWidth": 12, "gridHeight": 12 } + ] + }, + "slots": { + "widget-dashboardHome": "DashboardCustomView" + } }, { "id": "Organisaties", @@ -93,7 +102,7 @@ "type": "custom", "title": "Organisations", "component": "OrganisatieIndexView", - "_note": "TODO: manual migration required — custom page not auto-converted" + "_note": "Lib gap: bespoke OrganisatieCard + AddContactpersoonModal flow. Internally drives CnIndexPage but owns CRUD orchestration the manifest can't express: OrganisationModal create/edit/copy, AddContactpersoonModal, activate/deactivate status dialogs, _extend: contactpersonen on the collection fetch, URL-hash deep links (search/filters/page), and cross-component organisation* store subscriptions. Residual custom surface is the modal/dialog/deep-link wiring; collapse to type:'index' when the manifest gains modal+deep-link declarative wiring." }, { "id": "Contactpersonen", From 6ba425e55f139e4aedcc30142c56496503515cab Mon Sep 17 00:00:00 2001 From: Specter Intelligence Date: Wed, 20 May 2026 09:02:45 +0000 Subject: [PATCH 007/662] feat: Add OpenSpec change method-decomposition from Specter --- .../method-decomposition/context-brief.md | 311 +++++++++++ .../changes/method-decomposition/design.md | 314 +++++++++++ .../changes/method-decomposition/proposal.md | 150 ++++- .../specs/method-decomposition/spec.md | 514 +++++++++++------- .../changes/method-decomposition/tasks.md | 270 ++++++++- 5 files changed, 1347 insertions(+), 212 deletions(-) create mode 100644 openspec/changes/method-decomposition/context-brief.md create mode 100644 openspec/changes/method-decomposition/design.md diff --git a/openspec/changes/method-decomposition/context-brief.md b/openspec/changes/method-decomposition/context-brief.md new file mode 100644 index 00000000..dce87320 --- /dev/null +++ b/openspec/changes/method-decomposition/context-brief.md @@ -0,0 +1,311 @@ +--- +status: draft +priority: high +estimated_effort: large +--- + +# Method Decomposition -- SoftwareCatalog + +## Goal + +Eliminate 145 PHPMD complexity suppressions by decomposing complex methods into smaller, focused units. Each suppression represents a method or class that exceeds PHPMD's strict thresholds (CC>10, NPath>200, MethodLength>100, ClassLength>1000). The total codebase has 326 `@SuppressWarnings(PHPMD.*)` annotations; this spec targets the 145 that relate to structural complexity. + +## Current State + +- **CyclomaticComplexity suppressions:** 31 (methods with >10 branches) +- **NPathComplexity suppressions:** 26 (methods with >200 execution paths) +- **ExcessiveMethodLength suppressions:** 35 (methods >100 lines) +- **ExcessiveClassComplexity suppressions:** 19 (classes with too much logic) +- **ExcessiveClassLength suppressions:** 14 (classes >1000 lines) +- **CouplingBetweenObjects suppressions:** 12 (too many dependencies) +- **TooManyMethods suppressions:** 8 + +## Requirements + +### REQ-DECOMP-001: SettingsController Decomposition + +The `lib/Controller/SettingsController.php` (23 PHPMD suppressions) MUST be decomposed by extracting sync, module registration, and configuration logic into dedicated handler classes. The controller retains only thin action methods that delegate to handlers, reducing class-level complexity (ExcessiveClassLength, TooManyMethods, ExcessiveClassComplexity, CouplingBetweenObjects) and method-level complexity on `syncSoftwareCatalogue`, `registerModules`, `syncOrganizations`, and `configureArchiMate`. + +**Scenarios:** + +1. **GIVEN** SettingsController has a `syncSoftwareCatalogue()` method with CC>10, NPath>200, and >100 lines **WHEN** the method is decomposed **THEN** a `SyncHandler` class is created with `validateSyncConfig()`, `prepareSyncData()`, `executeSyncBatch()`, and `buildSyncResponse()` methods, and the controller delegates to `SyncHandler::handle()`. + +2. **GIVEN** SettingsController has `registerModules()` with ExcessiveMethodLength **WHEN** the method is decomposed **THEN** a `ModuleRegistrationHandler` class is created with `validateModuleInput()`, `resolveModuleDependencies()`, and `persistModules()` methods. + +3. **GIVEN** SettingsController injects 10+ dependencies (CouplingBetweenObjects) **WHEN** handlers are extracted **THEN** each handler receives only its required dependencies (e.g., SyncHandler gets ObjectService and SoftwareCatalogueService; ModuleRegistrationHandler gets ObjectService and ModuleRegistrationService), reducing the controller's constructor parameter count. + +4. **GIVEN** the decomposition is complete **WHEN** `composer check:strict` runs **THEN** PHPMD reports zero violations for SettingsController and all suppression annotations are removed from the file. + +5. **GIVEN** the decomposition is complete **WHEN** the existing unit tests run **THEN** all tests pass without modification (pure refactoring, public API unchanged). + +### REQ-DECOMP-002: SoftwareCatalogEventListener Decomposition + +The `lib/EventListener/SoftwareCatalogEventListener.php` (11 suppressions) MUST be decomposed by extracting event-specific handling logic into separate handler methods and helper classes. The monolithic `handleModuleCreated`, `handleModuleUpdated`, and `handleOrganizationEvent` methods each have CC>10, NPath>200, and >100 lines. + +**Scenarios:** + +1. **GIVEN** `handleModuleCreated()` has nested conditional logic for module type detection, schema lookup, and property mapping **WHEN** the method is decomposed **THEN** guard clauses extract early-return validation into `validateModuleEvent()`, type-specific logic is extracted into `processModuleByType()`, and schema mapping is extracted into `mapModuleToSchema()`. + +2. **GIVEN** `handleModuleUpdated()` shares 60% of its logic with `handleModuleCreated()` **WHEN** both methods are decomposed **THEN** shared logic is extracted into a `ModuleEventProcessor` helper class used by both handlers, eliminating code duplication. + +3. **GIVEN** `handleOrganizationEvent()` has >200 execution paths **WHEN** the method is decomposed **THEN** independent conditional blocks are extracted into `handleOrganizationCreate()`, `handleOrganizationUpdate()`, and `handleOrganizationDelete()` private methods, each with NPath <50. + +### REQ-DECOMP-003: ContactpersonenController Decomposition + +The `lib/Controller/ContactpersonenController.php` (11 suppressions) MUST be decomposed by extracting create/update validation, bulk import, and export logic. The `create()` and `update()` methods each exceed CC and method length thresholds. + +**Scenarios:** + +1. **GIVEN** `create()` has >100 lines of validation, data preparation, and persistence logic **WHEN** decomposed **THEN** validation is extracted into `validateContactInput(array $data): array`, data enrichment into `enrichContactData(array $data): array`, and persistence into `persistContact(array $data): JSONResponse`. + +2. **GIVEN** `bulkImport()` has ExcessiveMethodLength **WHEN** decomposed **THEN** CSV/JSON parsing is extracted into `parseImportFile()`, row validation into `validateImportRow()`, batch processing into `processImportBatch()`, and error collection into `buildImportReport()`. + +3. **GIVEN** `exportContacts()` has ExcessiveMethodLength **WHEN** decomposed **THEN** query building is extracted into `buildExportQuery()`, format conversion into `formatExportData()`, and response building into `buildExportResponse()`. + +4. **GIVEN** the controller has 3 class-level suppressions (ExcessiveClassLength, ExcessiveClassComplexity, CouplingBetweenObjects) **WHEN** handler extraction reduces class size **THEN** the controller class drops below 1000 lines and coupling drops below 13 dependencies. + +### REQ-DECOMP-004: SoftwareCatalogueService Decomposition + +The `lib/Service/SoftwareCatalogueService.php` (20 suppressions) MUST be decomposed by splitting into focused service classes. This core service handles VNG Software Catalogus API synchronization with multiple concerns: API communication, data mapping, conflict resolution, and progress tracking. + +**Scenarios:** + +1. **GIVEN** SoftwareCatalogueService has 7+ class-level suppressions indicating an oversized god-class **WHEN** decomposed **THEN** API communication methods move to `SoftwareCatalogue/ApiClient.php`, data mapping to `SoftwareCatalogue/DataMapper.php`, and conflict resolution to `SoftwareCatalogue/ConflictResolver.php`. + +2. **GIVEN** the codebase already has a `SoftwareCatalogue/` subdirectory with handler classes (ContactPersonHandler, OrganizationHandler, HierarchyHandler, GroupHandler) **WHEN** additional extraction follows this pattern **THEN** consistency is maintained and the existing handler injection pattern (constructor DI, delegation from parent service) is reused. + +3. **GIVEN** SoftwareCatalogueService methods contain progress tracking code interleaved with business logic **WHEN** decomposed **THEN** progress tracking calls are isolated to a ProgressTracker wrapper (which already exists at `lib/Service/ProgressTracker.php`), keeping business methods focused. + +### REQ-DECOMP-005: SettingsService Decomposition + +The `lib/Service/SettingsService.php` (23 suppressions) MUST be decomposed. This service manages application configuration persistence with methods that validate, transform, and store multiple configuration sections. The high coupling comes from accessing many configuration keys across different domains. + +**Scenarios:** + +1. **GIVEN** SettingsService handles sync settings, module settings, organization settings, and ArchiMate settings in one class **WHEN** decomposed **THEN** each configuration domain gets a dedicated handler: `SyncSettingsHandler`, `ModuleSettingsHandler`, `OrganizationSettingsHandler`, with SettingsService acting as a facade. + +2. **GIVEN** methods use deep conditional chains to validate configuration values **WHEN** decomposed **THEN** validation logic is extracted into `validate{Domain}Config()` methods using early returns and guard clauses, reducing CC below 10 per method. + +3. **GIVEN** the class has TooManyMethods suppression **WHEN** handler extraction moves groups of related methods to handlers **THEN** SettingsService retains only delegation methods (under 15 public methods). + +### REQ-DECOMP-006: ArchiMate Services Decomposition + +The `lib/Service/ArchiMateService.php` (18 suppressions), `lib/Service/ArchiMateImportService.php` (16 suppressions), and `lib/Service/ArchiMateExportService.php` (16 suppressions) MUST be decomposed. These services handle XML parsing, element-level processing, and relationship mapping with deeply nested loops and conditionals. + +**Scenarios:** + +1. **GIVEN** ArchiMateImportService has methods that parse XML elements with nested switch statements for element types **WHEN** decomposed **THEN** each element type handler is extracted into a dedicated method (`importElement()`, `importRelationship()`, `importView()`, `importDiagram()`), each under 50 lines. + +2. **GIVEN** ArchiMateExportService builds XML with deep conditional nesting for attribute handling **WHEN** decomposed **THEN** attribute builders are extracted into `buildElementAttributes()`, `buildRelationshipAttributes()`, and `buildViewAttributes()` helper methods. + +3. **GIVEN** ArchiMateService coordinates import and export with 7 class-level suppressions **WHEN** decomposed **THEN** orchestration logic is simplified by delegating to the import/export services (which themselves are now cleaner), and validation logic is extracted into `validateArchiMateFile()`. + +4. **GIVEN** all three services have CouplingBetweenObjects suppressions **WHEN** shared dependencies are grouped **THEN** a `ArchiMateContext` value object carries shared state (ObjectService, SettingsService, logger) reducing constructor parameter counts. + +### REQ-DECOMP-007: OrganizationSyncService Decomposition + +The `lib/Service/OrganizationSyncService.php` (7 class-level suppressions) MUST be decomposed by extracting sync logic into pipeline stages. The service pulls organization data from external sources with complex mapping, validation, and conflict resolution. + +**Scenarios:** + +1. **GIVEN** the sync method has >200 execution paths combining fetch, validate, transform, and persist phases **WHEN** decomposed **THEN** each phase becomes a private method: `fetchOrganizations()`, `validateOrganization()`, `transformOrganization()`, `persistOrganization()`, each with NPath <50. + +2. **GIVEN** the service handles both create and update flows with shared validation **WHEN** decomposed **THEN** shared validation is extracted into `validateOrganizationData()` called by both `handleCreate()` and `handleUpdate()`. + +3. **GIVEN** error handling is scattered throughout the sync method **WHEN** decomposed **THEN** error handling is centralized into `handleSyncError()` with consistent error logging and progress tracking. + +### REQ-DECOMP-008: ContactpersoonService Decomposition + +The `lib/Service/ContactpersoonService.php` (6 class-level suppressions) MUST be decomposed by extracting validation, enrichment, and persistence phases from the main business methods. + +**Scenarios:** + +1. **GIVEN** the service has methods exceeding CC>10 due to field-level validation checks **WHEN** decomposed **THEN** field validation is extracted into a `ContactValidator` helper with methods like `validateEmail()`, `validatePhone()`, `validateName()`, reducing CC below 10. + +2. **GIVEN** data enrichment logic (looking up organization, resolving duplicates) is interleaved with persistence **WHEN** decomposed **THEN** enrichment is extracted into `enrichContactData()` called before `persistContact()`. + +3. **GIVEN** the class has CouplingBetweenObjects suppression **WHEN** dependencies are analyzed **THEN** rarely-used dependencies (email service, export service) are lazy-loaded via ContainerInterface reducing immediate coupling. + +### REQ-DECOMP-009: AangebodenGebruikController and Service Decomposition + +The `lib/Controller/AangebodenGebruikController.php` (6 suppressions) and `lib/Service/AangebodenGebruikService.php` (5 suppressions) MUST be decomposed. The controller's `create()`, `bulkCreate()`, and `updateStatus()` methods exceed complexity thresholds. + +**Scenarios:** + +1. **GIVEN** `bulkCreate()` has ExcessiveMethodLength with batch processing, validation per item, and error aggregation **WHEN** decomposed **THEN** the method delegates to `validateBulkInput()`, `processBulkItem()`, and `aggregateBulkResults()` private methods. + +2. **GIVEN** `updateStatus()` has CC>10 due to status transition validation **WHEN** decomposed **THEN** status transition rules are extracted into a `StatusTransitionValidator` with a transition map, reducing the method to a simple `validate -> transition -> persist` flow. + +3. **GIVEN** the service has 5 class-level suppressions **WHEN** decomposed following the handler pattern **THEN** a `GebruikStatusHandler` and `GebruikBulkHandler` are created, each handling their specific concern. + +### REQ-DECOMP-010: ViewService and SymfonyEmailService Decomposition + +The `lib/Service/ViewService.php` (5 suppressions) and `lib/Service/SymfonyEmailService.php` (5 suppressions) MUST be decomposed. ViewService manages configurable data views with complex query building. SymfonyEmailService handles email composition with template rendering and attachment handling. + +**Scenarios:** + +1. **GIVEN** ViewService has methods that build complex queries with multiple optional filters **WHEN** decomposed **THEN** query building is extracted into a `ViewQueryBuilder` helper with chainable filter methods: `applyDateFilter()`, `applyStatusFilter()`, `applySearchFilter()`, `applySorting()`. + +2. **GIVEN** SymfonyEmailService composes emails with conditional template selection, attachment handling, and recipient resolution **WHEN** decomposed **THEN** email building is split into `resolveRecipients()`, `renderTemplate()`, `attachFiles()`, and `sendEmail()` methods. + +3. **GIVEN** both services have CyclomaticComplexity and NPathComplexity suppressions **WHEN** decomposed with early returns and guard clauses **THEN** each method has CC<10 and NPath<200 without needing suppressions. + +### REQ-DECOMP-011: Priority 2 File Decomposition + +The 8 files with 3-4 suppressions each (OrganizationHandler, ModuleComplianceService, AanbodService, UserProfileUpdatedEventListener, HierarchyHandler, ModuleRegistrationService, GebruikSyncService, OpenRegisterEventsDebugListener) MUST be decomposed to reduce their complexity below PHPMD thresholds. + +**Scenarios:** + +1. **GIVEN** ModuleComplianceService has 4 suppressions (class complexity, CC, NPath, method length) **WHEN** decomposed **THEN** compliance check logic is split into individual rule evaluators: `checkLicenseCompliance()`, `checkSecurityCompliance()`, `checkDocumentationCompliance()`, each returning a compliance result object. + +2. **GIVEN** UserProfileUpdatedEventListener has 4 suppressions across 2 methods **WHEN** decomposed **THEN** profile field mapping is extracted into a `ProfileFieldMapper` helper, and the event handling methods delegate to it. + +3. **GIVEN** HierarchyHandler has 3 suppressions for tree traversal complexity **WHEN** decomposed **THEN** tree operations are extracted into `buildHierarchyTree()`, `resolveParent()`, and `updateChildReferences()` methods. + +4. **GIVEN** all 8 files are decomposed **WHEN** the combined suppression count is checked **THEN** the total is reduced from approximately 28 to 0, contributing to the overall 145-suppression elimination goal. + +### REQ-DECOMP-012: Priority 3 File Cleanup + +The 6 files with 1-2 suppressions each (ModuleComplianceSubscriber, GebruikController, Application, GroupHandler, ModuleVersionService, ViewController) MUST be decomposed or refactored to remove remaining suppressions. + +**Scenarios:** + +1. **GIVEN** Application.php has CouplingBetweenObjects + ExcessiveMethodLength **WHEN** decomposed **THEN** event listener registration is extracted into a `EventRegistrar` helper, and service registration into `ServiceRegistrar`, reducing the boot method size. + +2. **GIVEN** ModuleVersionService has a single ExcessiveMethodLength **WHEN** decomposed **THEN** the long method is split into `fetchVersionData()`, `compareVersions()`, and `updateVersionRecord()` phases. + +3. **GIVEN** all 6 files are cleaned up **WHEN** `composer check:strict` runs **THEN** zero PHPMD violations remain across the entire codebase for the targeted suppression categories. + +## Decomposition Strategy + +### For CyclomaticComplexity (>10 branches) +Extract conditional branches into private helper methods: +- Guard clauses: Extract early-return validation into `validate{Thing}()` methods +- Switch-like logic: Extract case handlers into `handle{Case}()` methods +- Nested conditions: Flatten by extracting inner blocks into descriptive methods + +### For NPathComplexity (>200 paths) +Reduce execution paths by: +- Breaking method into pipeline stages (each stage = private method) +- Extracting independent conditional blocks into separate methods +- Using early returns to eliminate nested paths + +### For ExcessiveMethodLength (>100 lines) +Split long methods into logical phases: +- Validation phase -> `validate{Input}()` +- Preparation phase -> `prepare{Data}()` +- Processing phase -> `process{Thing}()` +- Response phase -> `build{Response}()` + +### For ExcessiveClassComplexity / ExcessiveClassLength +Extract method groups into Handler classes (existing pattern in codebase): +- Create `{ClassName}/{HandlerName}Handler.php` +- Move related methods to the handler +- Inject handler via constructor +- Delegate from original methods (keep public API stable) + +### For CouplingBetweenObjects (>13 dependencies) +Reduce constructor parameters by: +- Grouping related dependencies into a single service +- Using lazy loading for rarely-used dependencies (ContainerInterface->get()) +- Moving methods that use specific deps to handler classes + +## Files Requiring Decomposition + +### Priority 1 -- Highest complexity (files with 5+ suppressions) + +**lib/Controller/SettingsController.php** (23 suppressions) +Admin settings controller managing synchronization settings, module registration, and catalogue configuration. Class-level suppressions for class length, TooManyMethods, class complexity, and coupling. Method-level suppressions on `syncSoftwareCatalogue`, `registerModules`, `syncOrganizations`, and `configureArchiMate`. + +**lib/Service/SettingsService.php** (23 suppressions) +Settings persistence service managing application configuration across multiple domains. + +**lib/Service/SoftwareCatalogueService.php** (20 suppressions) +Core service for synchronizing with the VNG Software Catalogus API. + +**lib/Service/ArchiMateService.php** (18 suppressions) +ArchiMate enterprise architecture model import/export orchestrator. + +**lib/Service/ArchiMateImportService.php** (16 suppressions) +ArchiMate XML import service parsing Open Exchange Format files. + +**lib/Service/ArchiMateExportService.php** (16 suppressions) +ArchiMate XML export service generating Open Exchange Format files. + +**lib/EventListener/SoftwareCatalogEventListener.php** (11 suppressions) +Event listener handling OpenRegister object events for software catalog synchronization. + +**lib/Controller/ContactpersonenController.php** (11 suppressions) +Contact persons CRUD controller with complex create/update logic. + +**lib/Service/SoftwareCatalogue/ContactPersonHandler.php** (7 suppressions) +Handler for contact person synchronization with the Software Catalogus. + +**lib/Service/OrganizationSyncService.php** (7 suppressions) +Organisation synchronization service pulling data from external sources. + +**lib/Service/ContactpersoonService.php** (6 suppressions) +Contact person business logic service. + +**lib/Controller/AangebodenGebruikController.php** (6 suppressions) +"Offered usage" (software deployments) controller. + +**lib/Service/ViewService.php** (5 suppressions) +View/dashboard service managing configurable data views. + +**lib/Service/SymfonyEmailService.php** (5 suppressions) +Email sending service using Symfony Mailer. + +**lib/Service/AangebodenGebruikService.php** (5 suppressions) +Software usage/deployment business logic. + +### Priority 2 -- Medium complexity (files with 3-4 suppressions) + +- `lib/Service/SoftwareCatalogue/OrganizationHandler.php` (4) +- `lib/Service/ModuleComplianceService.php` (4) +- `lib/Service/AanbodService.php` (4) +- `lib/EventListener/UserProfileUpdatedEventListener.php` (4) +- `lib/Service/SoftwareCatalogue/HierarchyHandler.php` (3) +- `lib/Service/ModuleRegistrationService.php` (3) +- `lib/Service/GebruikSyncService.php` (3) +- `lib/EventListener/OpenRegisterEventsDebugListener.php` (3) + +### Priority 3 -- Single or double suppressions + +- `lib/EventListener/ModuleComplianceSubscriber.php` (2) +- `lib/Controller/GebruikController.php` (2) +- `lib/AppInfo/Application.php` (2) +- `lib/Service/SoftwareCatalogue/GroupHandler.php` (1) +- `lib/Service/ModuleVersionService.php` (1) +- `lib/Controller/ViewController.php` (1) + +## Testing Strategy + +### Before decomposition +1. Run existing unit tests: `docker exec -w /var/www/html/custom_apps/softwarecatalog nextcloud php vendor/bin/phpunit -c phpunit-unit.xml` +2. Note any pre-existing failures +3. Run PHPMD to record current suppression count: `./vendor/bin/phpmd lib/ text phpmd.xml 2>&1 | wc -l` + +### During decomposition (per method) +1. Verify `php -l` passes on all changed files +2. Run unit tests for the specific class: `--filter ClassName` +3. Run PHPMD on the specific file to confirm suppression can be removed + +### After decomposition +1. Full unit test suite passes +2. PHPMD reports 0 violations (no new warnings) +3. Total suppression count reduced by expected amount +4. `composer check:strict` passes +5. Manual smoke test in browser (http://localhost:3000) + +## Acceptance Criteria +- [ ] All CyclomaticComplexity suppressions eliminated or reduced to <=5 +- [ ] All NPathComplexity suppressions eliminated or reduced to <=5 +- [ ] All ExcessiveMethodLength suppressions eliminated or reduced to <=5 +- [ ] ExcessiveClassComplexity reduced by extracting handler classes +- [ ] CouplingBetweenObjects reduced by dependency grouping and handler extraction +- [ ] TooManyMethods reduced by handler extraction +- [ ] No new PHPMD violations introduced +- [ ] All existing tests continue to pass +- [ ] No behavioral changes (pure refactoring) +- [ ] `composer check:strict` passes with zero violations diff --git a/openspec/changes/method-decomposition/design.md b/openspec/changes/method-decomposition/design.md new file mode 100644 index 00000000..11b47174 --- /dev/null +++ b/openspec/changes/method-decomposition/design.md @@ -0,0 +1,314 @@ +# Design — method-decomposition + +> This change is a **pure PHP refactoring**. No new OpenRegister schemas are +> introduced or modified. The seed-data requirement (ADR-001) does NOT apply — +> there are no schema introductions or modifications in this change. + +## Reuse Analysis + +Per ADR-001, any capability must check for overlap with existing OpenRegister +services before building new code. This change adds no net-new capability; +it reorganises existing code using patterns already present in the codebase. + +| Capability | Reuse from | Notes | +|------------|-----------|-------| +| Handler pattern | `lib/Service/SoftwareCatalogue/ContactPersonHandler`, `OrganizationHandler`, `HierarchyHandler`, `GroupHandler` | Existing pattern. New handlers follow the same constructor-DI + delegation contract. | +| Progress tracking | `lib/Service/ProgressTracker.php` | Already exists. `SoftwareCatalogueService` must delegate all progress calls to it instead of inlining them. | +| Constructor DI | Nextcloud DI container | All new handler classes are wired via constructor injection. No `\OC::$server` or static locators per ADR-003. | +| Config access | `IAppConfig` | Settings domain handlers continue to use `IAppConfig`. No new config mechanism introduced. | +| PHPMD tooling | `./vendor/bin/phpmd` + `phpmd.xml` | The existing rule set is the target. No new tooling needed. | + +### What we deliberately do NOT build + +- **Custom PHPMD runner** — `composer check:strict` already runs PHPMD via + `phpmd.xml`. No tooling additions required. +- **New ObjectService wrappers** — this change does not touch data access. All + existing `ObjectService::findObject()` / `saveObject()` call sites remain in + place, moved wholesale into their new handler classes. +- **New public API endpoints** — pure internal refactoring. No routes change. +- **New OpenRegister schemas** — no `lib/Settings/` register template changes. + +### Deduplication check + +Searched `lib/Service/SoftwareCatalogue/` for existing handlers to avoid +re-creating them: + +| Existing file | Suppressions | Action | +|--------------|-------------|--------| +| `lib/Service/SoftwareCatalogue/ContactPersonHandler.php` | 7 | Decompose in place (private method extraction) | +| `lib/Service/SoftwareCatalogue/OrganizationHandler.php` | 4 | Decompose in place | +| `lib/Service/SoftwareCatalogue/HierarchyHandler.php` | 3 | Decompose in place | +| `lib/Service/SoftwareCatalogue/GroupHandler.php` | 1 | Decompose in place | +| `lib/Service/ProgressTracker.php` | 0 | Reuse — isolate progress calls from business logic | + +No new capability duplicates existing OpenRegister platform services. New +handler classes (SyncHandler, ModuleRegistrationHandler, etc.) are +app-internal domain logic with no equivalent in OpenRegister. + +## Architecture + +### The Handler Pattern + +The existing `lib/Service/SoftwareCatalogue/` subdirectory establishes the +pattern. New handlers follow the same contract: + +```php +// New handler class (example: SyncHandler) +class SyncHandler +{ + // @spec openspec/changes/method-decomposition/tasks.md#task-1 + public function __construct( + private readonly ObjectService $objectService, + private readonly SoftwareCatalogueService $catalogueService, + ) {} + + public function handle(array $config): array + { + $validated = $this->validateSyncConfig($config); + $data = $this->prepareSyncData($validated); + $result = $this->executeSyncBatch($data); + return $this->buildSyncResponse($result); + } + + private function validateSyncConfig(array $config): array { /* CC<4 */ } + private function prepareSyncData(array $config): array { /* CC<4 */ } + private function executeSyncBatch(array $data): array { /* CC<5 */ } + private function buildSyncResponse(array $result): array { /* CC<3 */ } +} + +// Original controller becomes thin +class SettingsController +{ + public function __construct( + private readonly SyncHandler $syncHandler, + // fewer deps — SyncHandler owns ObjectService + CatalogueService + ) {} + + public function syncSoftwareCatalogue(): JSONResponse + { + // <10 lines per ADR-003 + return new JSONResponse($this->syncHandler->handle($this->request->getParams())); + } +} +``` + +### Decomposition Strategies + +#### Strategy A: Private method extraction (CyclomaticComplexity / NPathComplexity / ExcessiveMethodLength) + +For methods that are long or branchy but do not warrant a new class: + +```php +// Before: 120-line method, CC=14, NPath=340 +public function handleOrganizationEvent(Event $event): void +{ + if ($event->getType() === 'create') { + if ($event->getOrganization() !== null) { + // 40 lines of create logic + if ($someCondition) { /* nested */ } + } + } elseif ($event->getType() === 'update') { + // 40 lines of update logic + } else { + // 30 lines of delete logic + } +} + +// After: orchestrator + private helpers, CC=3, NPath<50 per method +public function handleOrganizationEvent(Event $event): void +{ + match($event->getType()) { + 'create' => $this->handleOrganizationCreate($event), + 'update' => $this->handleOrganizationUpdate($event), + default => $this->handleOrganizationDelete($event), + }; +} + +private function handleOrganizationCreate(Event $event): void { /* CC<5 */ } +private function handleOrganizationUpdate(Event $event): void { /* CC<5 */ } +private function handleOrganizationDelete(Event $event): void { /* CC<5 */ } +``` + +#### Strategy B: Handler class extraction (ExcessiveClassLength / ExcessiveClassComplexity / TooManyMethods) + +For oversized classes, extract cohesive method groups into dedicated handlers: + +```php +// Before: SettingsController with 23 suppressions, 10+ constructor deps + +// After: handlers own their deps +class SettingsController { + public function __construct( + private readonly SyncHandler $syncHandler, + private readonly ModuleRegistrationHandler $moduleHandler, + // 3-4 remaining deps instead of 10+ + ) {} +} + +class SyncHandler { + public function __construct( + private readonly ObjectService $objectService, + private readonly SoftwareCatalogueService $catalogueService, + ) {} +} + +class ModuleRegistrationHandler { + public function __construct( + private readonly ObjectService $objectService, + private readonly ModuleRegistrationService $moduleService, + ) {} +} +``` + +#### Strategy C: Guard clauses (CyclomaticComplexity) + +Replace nested conditionals with early returns to eliminate execution paths: + +```php +// Before: deeply nested, CC=12 +public function handleModuleCreated(Event $event): void +{ + if ($event->getModule() !== null) { + if ($this->isValidType($event->getModule())) { + if ($this->schemaExists($event->getModule())) { + // ... main logic 80 lines + } + } + } +} + +// After: guard clauses + delegation, CC=4 +public function handleModuleCreated(Event $event): void +{ + if (!$this->validateModuleEvent($event)) { + return; + } + $this->processModuleByType($event->getModule()); +} + +private function validateModuleEvent(Event $event): bool +{ + return $event->getModule() !== null + && $this->isValidType($event->getModule()) + && $this->schemaExists($event->getModule()); +} + +private function processModuleByType(Module $module): void { /* CC<5 */ } +``` + +#### Strategy D: Dependency grouping (CouplingBetweenObjects) + +For classes with >13 constructor parameters, group shared infrastructure: + +```php +// ArchiMateContext carries shared infrastructure deps +class ArchiMateContext +{ + public function __construct( + public readonly ObjectService $objectService, + public readonly SettingsService $settingsService, + public readonly LoggerInterface $logger, + ) {} +} + +// Services inject the context instead of 3 individual deps +class ArchiMateImportService +{ + public function __construct( + private readonly ArchiMateContext $context, + // domain-specific deps only + ) {} +} +``` + +## Handler File Layout + +New handler files follow the existing `SoftwareCatalogue/` naming convention. +All new files MUST include an SPDX header and `@spec` PHPDoc tags per ADR-003 +and ADR-015. + +``` +lib/ + Controller/ + Settings/ + SyncHandler.php (NEW — REQ-DECOMP-001) + ModuleRegistrationHandler.php (NEW — REQ-DECOMP-001) + Service/ + SoftwareCatalogue/ + ApiClient.php (NEW — REQ-DECOMP-004) + DataMapper.php (NEW — REQ-DECOMP-004) + ConflictResolver.php (NEW — REQ-DECOMP-004) + Settings/ + SyncSettingsHandler.php (NEW — REQ-DECOMP-005) + ModuleSettingsHandler.php (NEW — REQ-DECOMP-005) + OrganizationSettingsHandler.php (NEW — REQ-DECOMP-005) + ArchiMate/ + ArchiMateContext.php (NEW — REQ-DECOMP-006) + AangebodenGebruik/ + GebruikStatusHandler.php (NEW — REQ-DECOMP-009) + GebruikBulkHandler.php (NEW — REQ-DECOMP-009) + StatusTransitionValidator.php (NEW — REQ-DECOMP-009) + Contactpersoon/ + ContactValidator.php (NEW — REQ-DECOMP-008) + ModuleEventProcessor.php (NEW — REQ-DECOMP-002) + ViewQueryBuilder.php (NEW — REQ-DECOMP-010) + ProfileFieldMapper.php (NEW — REQ-DECOMP-011) + EventRegistrar.php (NEW — REQ-DECOMP-012) + ServiceRegistrar.php (NEW — REQ-DECOMP-012) +``` + +### Decomposition sequencing + +Order matters — downstream handlers must not depend on upstream classes that +are still oversized: + +1. `SettingsService` (REQ-DECOMP-005) — decompose first; ArchiMateContext + depends on its post-refactor facade. +2. `SoftwareCatalogueService` (REQ-DECOMP-004) — before decomposing its callers. +3. `SettingsController` (REQ-DECOMP-001) — after SettingsService is clean. +4. `ArchiMate*` services (REQ-DECOMP-006) — after SettingsService. +5. All remaining Priority 1 files independently. +6. Priority 2 and 3 files last. + +## Migration Risk Surface + +| Risk | Mitigation | +|------|-----------| +| Handler extraction silently changes behavior | Unit tests must pass before and after each extraction. No logic changes — only code movement. | +| New handler class introduces new PHPMD violations | Run `./vendor/bin/phpmd {file} text phpmd.xml` per new file during implementation. Fix before committing. | +| Constructor DI fails in container | Nextcloud auto-wires by type when all deps are type-hinted. Verify with `php -l` + DI smoke test after each class. | +| Moving private methods changes semantics | Extract one method at a time. Run `php -l` + `phpunit --filter ClassName` per step. | +| ArchiMateContext groups wrong deps | Analyze each service individually before grouping. Only truly shared infrastructure deps go into context. | +| Coupling count stays high after extraction | Track dep count before/after per class. If still >13 after handler extraction, apply `ContainerInterface` lazy-loading for edge-case deps. | +| `@spec` PHPDoc tags missing on new files | ADR-003 requires `@spec openspec/changes/method-decomposition/tasks.md#task-N` on every new class and public method. Apply during file creation, not after. | +| SettingsService facade breaks ArchiMate services | Sequence: decompose SettingsService first. ArchiMateContext uses the facade, not the original class. | + +## Open Design Questions + +1. **Q1 — Settings handler subdirectory convention.** Should settings handlers + live at `lib/Service/Settings/` (new subdirectory, mirroring the controller's + `lib/Controller/Settings/`) or as peer files in `lib/Service/`? Recommend: + `lib/Service/Settings/` for consistency with the `SoftwareCatalogue/` + subdirectory pattern. + +2. **Q2 — ArchiMateContext scope.** Should `ArchiMateContext` carry + `SettingsService`, `ObjectService`, and `LoggerInterface` — or only the + first two? Logger is used in every service. Recommend: include logger to + maximally reduce constructor coupling for all three ArchiMate services. + +3. **Q3 — ContactValidator placement.** Peer service at + `lib/Service/ContactValidator.php` vs. subdirectory at + `lib/Service/Contactpersoon/ContactValidator.php`? Recommend: subdirectory + for consistency with the `SoftwareCatalogue/` pattern. + +4. **Q4 — StatusTransitionValidator sharing.** Both + `AangebodenGebruikController` and `AangebodenGebruikService` have status + transition logic. Should `StatusTransitionValidator` be shared between + layers? Recommend: place in `lib/Service/AangebodenGebruik/` and inject into + both controller and service (service receives it via DI; controller delegates + to service, which uses the validator). + +5. **Q5 — ModuleEventProcessor as service vs. helper.** Should + `ModuleEventProcessor` be a standalone class injected via DI, or a + `final class` instantiated inline by the event listener? Recommend: DI + injection for testability (mirrors handler pattern). diff --git a/openspec/changes/method-decomposition/proposal.md b/openspec/changes/method-decomposition/proposal.md index 850bb6c7..c9ab8c68 100644 --- a/openspec/changes/method-decomposition/proposal.md +++ b/openspec/changes/method-decomposition/proposal.md @@ -1,12 +1,144 @@ -# Method Decomposition +# Method Decomposition — SoftwareCatalog -## Summary -Eliminate 145 PHPMD complexity suppressions by decomposing complex methods into smaller, focused units. +## Why -## Motivation -Improve code quality and maintainability by reducing method complexity below PHPMD thresholds. +SoftwareCatalog has accumulated 326 `@SuppressWarnings(PHPMD.*)` annotations +across its `lib/` directory. Of these, **145 relate to structural complexity**: +CyclomaticComplexity (31), NPathComplexity (26), ExcessiveMethodLength (35), +ExcessiveClassComplexity (19), ExcessiveClassLength (14), +CouplingBetweenObjects (12), and TooManyMethods (8). -## Scope -- Decompose SettingsController, ArchimateService, EnrichService, and other complex classes -- Extract handler classes for distinct responsibilities -- Remove PHPMD suppression annotations +Each annotation suppresses a real quality signal: a method or class that is too +large or too complex to safely review, test, or modify. Suppressions are +bypassed gates — `composer check:strict` enforces strict PHPMD thresholds, and +every suppression is a rule exemption that hides real complexity debt. + +The immediate cost is operational: PR reviewers cannot trust static analysis +output for affected files, making regression risk invisible. + +## What Changes + +Decompose the 29 files that carry these 145 suppressions using three mechanical +strategies aligned to ADR-003's Controller → Service layer contract: + +1. **Private method extraction** — break long methods into named pipeline + stages (`validate → prepare → process → respond`) each ≤50 lines and CC<10. +2. **Handler class extraction** — for oversized classes, move cohesive method + groups to dedicated `{Class}/{HandlerName}Handler.php` files, following the + existing `lib/Service/SoftwareCatalogue/` handler pattern already in the + codebase (ContactPersonHandler, OrganizationHandler, HierarchyHandler, + GroupHandler). +3. **Dependency grouping** — reduce constructor coupling by injecting handler + classes (which bundle their own dependencies) or lazy-loading via + `ContainerInterface` for rarely-used dependencies. + +All changes are **pure refactoring**: no new public API, no behavioral change, +no schema additions, no frontend changes. + +### Priority 1 — Highest complexity (5+ suppressions, 15 files) + +| File | Suppressions | Primary strategy | +|------|-------------|-----------------| +| `lib/Controller/SettingsController.php` | 23 | Handler extraction: SyncHandler, ModuleRegistrationHandler | +| `lib/Service/SettingsService.php` | 23 | Handler extraction: SyncSettingsHandler, ModuleSettingsHandler, OrganizationSettingsHandler | +| `lib/Service/SoftwareCatalogueService.php` | 20 | Sub-service extraction: ApiClient, DataMapper, ConflictResolver | +| `lib/Service/ArchiMateService.php` | 18 | Private method extraction + ArchiMateContext value object | +| `lib/Service/ArchiMateImportService.php` | 16 | Element-type handler methods | +| `lib/Service/ArchiMateExportService.php` | 16 | Attribute builder methods | +| `lib/EventListener/SoftwareCatalogEventListener.php` | 11 | Guard clauses + ModuleEventProcessor helper | +| `lib/Controller/ContactpersonenController.php` | 11 | Handler extraction: validate/enrich/persist phases | +| `lib/Service/SoftwareCatalogue/ContactPersonHandler.php` | 7 | Private method decomposition | +| `lib/Service/OrganizationSyncService.php` | 7 | Pipeline stage methods | +| `lib/Service/ContactpersoonService.php` | 6 | ContactValidator helper | +| `lib/Controller/AangebodenGebruikController.php` | 6 | StatusTransitionValidator | +| `lib/Service/ViewService.php` | 5 | ViewQueryBuilder helper | +| `lib/Service/SymfonyEmailService.php` | 5 | Private builder methods | +| `lib/Service/AangebodenGebruikService.php` | 5 | GebruikStatusHandler, GebruikBulkHandler | + +### Priority 2 — Medium complexity (3–4 suppressions, 8 files) + +`lib/Service/SoftwareCatalogue/OrganizationHandler.php` (4), +`lib/Service/ModuleComplianceService.php` (4), +`lib/Service/AanbodService.php` (4), +`lib/EventListener/UserProfileUpdatedEventListener.php` (4), +`lib/Service/SoftwareCatalogue/HierarchyHandler.php` (3), +`lib/Service/ModuleRegistrationService.php` (3), +`lib/Service/GebruikSyncService.php` (3), +`lib/EventListener/OpenRegisterEventsDebugListener.php` (3). + +### Priority 3 — Low complexity (1–2 suppressions, 6 files) + +`lib/EventListener/ModuleComplianceSubscriber.php` (2), +`lib/Controller/GebruikController.php` (2), +`lib/AppInfo/Application.php` (2), +`lib/Service/SoftwareCatalogue/GroupHandler.php` (1), +`lib/Service/ModuleVersionService.php` (1), +`lib/Controller/ViewController.php` (1). + +## Problem + +The suppressions are concentrated in controllers and services that grew +organically without a size budget. The root causes are: + +- **Sync methods** that mix API fetch, data mapping, validation, conflict + resolution, and progress tracking in a single method body. +- **Controller methods** that validate, enrich, and persist instead of + delegating to services (violating ADR-003's "thin controller" contract). +- **ArchiMate services** with switch-heavy XML parsers covering all element and + relationship types inline. +- **Settings service** that manages four independent configuration domains + (sync, modules, organisations, ArchiMate) in a single class. + +Each PHPMD category identifies a distinct problem: + +| Category | Threshold | Meaning | +|----------|-----------|---------| +| `CyclomaticComplexity` | >10 branches | Method is too branchy to unit-test exhaustively | +| `NPathComplexity` | >200 paths | Method has too many execution paths to reason about | +| `ExcessiveMethodLength` | >100 lines | Method is too long to review as a unit | +| `CouplingBetweenObjects` | >13 deps | Class knows too many other classes | +| `ExcessiveClassLength` | >1000 lines | Class scope is too broad | +| `ExcessiveClassComplexity` | — | Class-level aggregate complexity too high | +| `TooManyMethods` | — | Class responsibilities too dispersed | + +## Proposed Solution + +Apply the **Handler pattern** that already exists in +`lib/Service/SoftwareCatalogue/`: create dedicated handler classes that receive +only their required dependencies, keep the original class's public API +unchanged, and delegate from the original's action methods. + +``` +OriginalClass::publicAction() + → injects HandlerA::handle() // owns its 2-3 deps + → injects HandlerB::handle() // owns its 2-3 deps +``` + +Private-method decomposition (validate/prepare/process/respond) handles +method-level complexity without needing a new class. Guard clauses eliminate +nested conditionals with early returns. + +The `ProgressTracker` service (`lib/Service/ProgressTracker.php`) MUST be used +to isolate progress tracking from business logic in SoftwareCatalogueService. + +## Out of Scope + +- Behavioral changes: public API, request/response shapes, and database effects + are UNCHANGED. This is a pure refactoring. +- New features: no new functionality is added. +- Schema changes: no OpenRegister schemas are modified or added. +- Frontend changes: only PHP `lib/` files are modified. +- VNG `Softwarecatalogus/` client repo: read-only per project policy. +- Test infrastructure reorganisation: existing tests must pass unchanged. + +## See Also + +- `specs/method-decomposition/spec.md` — full GIVEN/WHEN/THEN requirement scenarios +- `design.md` — handler file layout, code shapes before/after, risk surface +- `tasks.md` — phase-based implementation checklist +- ADR-003 (`.claude/openspec/architecture/adr-003-backend.md`) — Controller → Service → Mapper contract and thin-controller rule +- ADR-008 (`.claude/openspec/architecture/adr-008-testing.md`) — PHPUnit and container invocation requirements +- ADR-015 (`.claude/openspec/architecture/adr-015-common-patterns.md`) — SPDX headers, error response patterns, pre-commit checklist +- `lib/Service/SoftwareCatalogue/` — existing handler pattern in the codebase +- `lib/Service/ProgressTracker.php` — existing progress tracking service to reuse +- `openspec/changes/softwarecatalog-legacy-quality-cleanup/` — the broader quality-gates burn-down that this change feeds into diff --git a/openspec/changes/method-decomposition/specs/method-decomposition/spec.md b/openspec/changes/method-decomposition/specs/method-decomposition/spec.md index dce87320..c2a6511e 100644 --- a/openspec/changes/method-decomposition/specs/method-decomposition/spec.md +++ b/openspec/changes/method-decomposition/specs/method-decomposition/spec.md @@ -4,308 +4,440 @@ priority: high estimated_effort: large --- -# Method Decomposition -- SoftwareCatalog +# Method Decomposition — SoftwareCatalog -## Goal +## Purpose -Eliminate 145 PHPMD complexity suppressions by decomposing complex methods into smaller, focused units. Each suppression represents a method or class that exceeds PHPMD's strict thresholds (CC>10, NPath>200, MethodLength>100, ClassLength>1000). The total codebase has 326 `@SuppressWarnings(PHPMD.*)` annotations; this spec targets the 145 that relate to structural complexity. +Specify the requirements for eliminating 145 PHPMD complexity suppressions in +`lib/` by decomposing complex methods and classes into smaller, focused units. +Each suppression bypasses a strict PHPMD threshold (CC>10, NPath>200, +MethodLength>100, ClassLength>1000). This is a pure refactoring change — no +behavioral changes, no schema modifications, no new public API. -## Current State +**Current suppression inventory:** -- **CyclomaticComplexity suppressions:** 31 (methods with >10 branches) -- **NPathComplexity suppressions:** 26 (methods with >200 execution paths) -- **ExcessiveMethodLength suppressions:** 35 (methods >100 lines) -- **ExcessiveClassComplexity suppressions:** 19 (classes with too much logic) -- **ExcessiveClassLength suppressions:** 14 (classes >1000 lines) -- **CouplingBetweenObjects suppressions:** 12 (too many dependencies) -- **TooManyMethods suppressions:** 8 +| Category | Count | Threshold | +|----------|-------|-----------| +| ExcessiveMethodLength | 35 | >100 lines | +| CyclomaticComplexity | 31 | >10 branches | +| NPathComplexity | 26 | >200 paths | +| ExcessiveClassComplexity | 19 | — | +| ExcessiveClassLength | 14 | >1000 lines | +| CouplingBetweenObjects | 12 | >13 deps | +| TooManyMethods | 8 | — | -## Requirements +## ADDED Requirements ### REQ-DECOMP-001: SettingsController Decomposition -The `lib/Controller/SettingsController.php` (23 PHPMD suppressions) MUST be decomposed by extracting sync, module registration, and configuration logic into dedicated handler classes. The controller retains only thin action methods that delegate to handlers, reducing class-level complexity (ExcessiveClassLength, TooManyMethods, ExcessiveClassComplexity, CouplingBetweenObjects) and method-level complexity on `syncSoftwareCatalogue`, `registerModules`, `syncOrganizations`, and `configureArchiMate`. +`lib/Controller/SettingsController.php` (23 PHPMD suppressions) MUST be +decomposed by extracting sync, module registration, and configuration logic +into dedicated handler classes. The controller MUST retain only thin action +methods (≤10 lines per ADR-003) that delegate to handlers. Class-level +suppressions (ExcessiveClassLength, TooManyMethods, ExcessiveClassComplexity, +CouplingBetweenObjects) and method-level suppressions on `syncSoftwareCatalogue`, +`registerModules`, `syncOrganizations`, and `configureArchiMate` MUST all be +removed. -**Scenarios:** +#### Scenario: syncSoftwareCatalogue decomposed into SyncHandler -1. **GIVEN** SettingsController has a `syncSoftwareCatalogue()` method with CC>10, NPath>200, and >100 lines **WHEN** the method is decomposed **THEN** a `SyncHandler` class is created with `validateSyncConfig()`, `prepareSyncData()`, `executeSyncBatch()`, and `buildSyncResponse()` methods, and the controller delegates to `SyncHandler::handle()`. +- GIVEN `SettingsController::syncSoftwareCatalogue()` has CC>10, NPath>200, and >100 lines +- WHEN the method is decomposed +- THEN a `lib/Controller/Settings/SyncHandler.php` class MUST be created +- AND it MUST expose `validateSyncConfig()`, `prepareSyncData()`, `executeSyncBatch()`, and `buildSyncResponse()` private methods +- AND the controller MUST delegate to `SyncHandler::handle()` in ≤10 lines -2. **GIVEN** SettingsController has `registerModules()` with ExcessiveMethodLength **WHEN** the method is decomposed **THEN** a `ModuleRegistrationHandler` class is created with `validateModuleInput()`, `resolveModuleDependencies()`, and `persistModules()` methods. +#### Scenario: registerModules decomposed into ModuleRegistrationHandler -3. **GIVEN** SettingsController injects 10+ dependencies (CouplingBetweenObjects) **WHEN** handlers are extracted **THEN** each handler receives only its required dependencies (e.g., SyncHandler gets ObjectService and SoftwareCatalogueService; ModuleRegistrationHandler gets ObjectService and ModuleRegistrationService), reducing the controller's constructor parameter count. +- GIVEN `SettingsController::registerModules()` has ExcessiveMethodLength +- WHEN the method is decomposed +- THEN a `lib/Controller/Settings/ModuleRegistrationHandler.php` class MUST be created +- AND it MUST expose `validateModuleInput()`, `resolveModuleDependencies()`, and `persistModules()` private methods -4. **GIVEN** the decomposition is complete **WHEN** `composer check:strict` runs **THEN** PHPMD reports zero violations for SettingsController and all suppression annotations are removed from the file. +#### Scenario: Constructor coupling reduced -5. **GIVEN** the decomposition is complete **WHEN** the existing unit tests run **THEN** all tests pass without modification (pure refactoring, public API unchanged). +- GIVEN `SettingsController` injects 10+ dependencies (CouplingBetweenObjects) +- WHEN handlers are extracted +- THEN `SyncHandler` MUST receive only `ObjectService` and `SoftwareCatalogueService` +- AND `ModuleRegistrationHandler` MUST receive only `ObjectService` and `ModuleRegistrationService` +- AND the controller's constructor parameter count MUST drop below 13 + +#### Scenario: composer check:strict passes with no suppressions + +- GIVEN the decomposition is complete +- WHEN `composer check:strict` runs +- THEN PHPMD MUST report zero violations for `SettingsController.php` +- AND all `@SuppressWarnings(PHPMD.*)` annotations MUST be removed from the file + +#### Scenario: Existing tests pass unchanged + +- GIVEN the decomposition is complete +- WHEN the existing PHPUnit tests run +- THEN all tests MUST pass without modification +- AND no behavioral change MUST occur (pure refactoring) ### REQ-DECOMP-002: SoftwareCatalogEventListener Decomposition -The `lib/EventListener/SoftwareCatalogEventListener.php` (11 suppressions) MUST be decomposed by extracting event-specific handling logic into separate handler methods and helper classes. The monolithic `handleModuleCreated`, `handleModuleUpdated`, and `handleOrganizationEvent` methods each have CC>10, NPath>200, and >100 lines. +`lib/EventListener/SoftwareCatalogEventListener.php` (11 suppressions) MUST be +decomposed by extracting event-specific handling logic into guard-clause-gated +helper methods and a shared `ModuleEventProcessor` class. The monolithic +`handleModuleCreated`, `handleModuleUpdated`, and `handleOrganizationEvent` +methods each have CC>10, NPath>200, and >100 lines. -**Scenarios:** +#### Scenario: handleModuleCreated decomposed with guard clauses -1. **GIVEN** `handleModuleCreated()` has nested conditional logic for module type detection, schema lookup, and property mapping **WHEN** the method is decomposed **THEN** guard clauses extract early-return validation into `validateModuleEvent()`, type-specific logic is extracted into `processModuleByType()`, and schema mapping is extracted into `mapModuleToSchema()`. +- GIVEN `handleModuleCreated()` has nested conditional logic for module type detection, schema lookup, and property mapping +- WHEN the method is decomposed +- THEN guard clauses MUST extract early-return validation into a `validateModuleEvent()` private method +- AND type-specific logic MUST be extracted into `processModuleByType()` +- AND schema mapping MUST be extracted into `mapModuleToSchema()` +- AND each extracted method MUST have CC<5 -2. **GIVEN** `handleModuleUpdated()` shares 60% of its logic with `handleModuleCreated()` **WHEN** both methods are decomposed **THEN** shared logic is extracted into a `ModuleEventProcessor` helper class used by both handlers, eliminating code duplication. +#### Scenario: Shared logic extracted into ModuleEventProcessor -3. **GIVEN** `handleOrganizationEvent()` has >200 execution paths **WHEN** the method is decomposed **THEN** independent conditional blocks are extracted into `handleOrganizationCreate()`, `handleOrganizationUpdate()`, and `handleOrganizationDelete()` private methods, each with NPath <50. +- GIVEN `handleModuleUpdated()` shares 60% of its logic with `handleModuleCreated()` +- WHEN both methods are decomposed +- THEN shared logic MUST be extracted into a `ModuleEventProcessor` helper class +- AND both handlers MUST delegate to `ModuleEventProcessor` +- AND code duplication between the two handlers MUST be eliminated + +#### Scenario: handleOrganizationEvent split into three methods + +- GIVEN `handleOrganizationEvent()` has >200 execution paths +- WHEN the method is decomposed +- THEN independent conditional blocks MUST be extracted into `handleOrganizationCreate()`, `handleOrganizationUpdate()`, and `handleOrganizationDelete()` private methods +- AND each extracted method MUST have NPath<50 ### REQ-DECOMP-003: ContactpersonenController Decomposition -The `lib/Controller/ContactpersonenController.php` (11 suppressions) MUST be decomposed by extracting create/update validation, bulk import, and export logic. The `create()` and `update()` methods each exceed CC and method length thresholds. +`lib/Controller/ContactpersonenController.php` (11 suppressions) MUST be +decomposed by extracting create/update validation, bulk import, and export +logic. The `create()` and `update()` methods each exceed CC and method length +thresholds. + +#### Scenario: create() decomposed into validate/enrich/persist phases -**Scenarios:** +- GIVEN `create()` has >100 lines of validation, data preparation, and persistence logic +- WHEN decomposed +- THEN validation MUST be extracted into `validateContactInput(array $data): array` +- AND data enrichment MUST be extracted into `enrichContactData(array $data): array` +- AND persistence MUST be extracted into `persistContact(array $data): JSONResponse` +- AND each extracted method MUST have CC<10 -1. **GIVEN** `create()` has >100 lines of validation, data preparation, and persistence logic **WHEN** decomposed **THEN** validation is extracted into `validateContactInput(array $data): array`, data enrichment into `enrichContactData(array $data): array`, and persistence into `persistContact(array $data): JSONResponse`. +#### Scenario: bulkImport() decomposed into parse/validate/process/report -2. **GIVEN** `bulkImport()` has ExcessiveMethodLength **WHEN** decomposed **THEN** CSV/JSON parsing is extracted into `parseImportFile()`, row validation into `validateImportRow()`, batch processing into `processImportBatch()`, and error collection into `buildImportReport()`. +- GIVEN `bulkImport()` has ExcessiveMethodLength with batch processing, per-item validation, and error aggregation +- WHEN decomposed +- THEN CSV/JSON parsing MUST be extracted into `parseImportFile()` +- AND row validation into `validateImportRow()` +- AND batch processing into `processImportBatch()` +- AND error collection into `buildImportReport()` -3. **GIVEN** `exportContacts()` has ExcessiveMethodLength **WHEN** decomposed **THEN** query building is extracted into `buildExportQuery()`, format conversion into `formatExportData()`, and response building into `buildExportResponse()`. +#### Scenario: exportContacts() decomposed -4. **GIVEN** the controller has 3 class-level suppressions (ExcessiveClassLength, ExcessiveClassComplexity, CouplingBetweenObjects) **WHEN** handler extraction reduces class size **THEN** the controller class drops below 1000 lines and coupling drops below 13 dependencies. +- GIVEN `exportContacts()` has ExcessiveMethodLength +- WHEN decomposed +- THEN query building MUST be extracted into `buildExportQuery()` +- AND format conversion into `formatExportData()` +- AND response building into `buildExportResponse()` + +#### Scenario: Class-level suppressions removed + +- GIVEN the controller has 3 class-level suppressions (ExcessiveClassLength, ExcessiveClassComplexity, CouplingBetweenObjects) +- WHEN handler extraction reduces class size +- THEN the controller class MUST drop below 1000 lines +- AND coupling MUST drop below 13 dependencies ### REQ-DECOMP-004: SoftwareCatalogueService Decomposition -The `lib/Service/SoftwareCatalogueService.php` (20 suppressions) MUST be decomposed by splitting into focused service classes. This core service handles VNG Software Catalogus API synchronization with multiple concerns: API communication, data mapping, conflict resolution, and progress tracking. +`lib/Service/SoftwareCatalogueService.php` (20 suppressions) MUST be +decomposed by splitting into focused service classes. This core service handles +VNG Software Catalogus API synchronization with multiple concerns: API +communication, data mapping, conflict resolution, and progress tracking. + +#### Scenario: Concerns extracted into sub-services -**Scenarios:** +- GIVEN `SoftwareCatalogueService` has 7+ class-level suppressions indicating an oversized god-class +- WHEN decomposed +- THEN API communication methods MUST move to `lib/Service/SoftwareCatalogue/ApiClient.php` +- AND data mapping MUST move to `lib/Service/SoftwareCatalogue/DataMapper.php` +- AND conflict resolution MUST move to `lib/Service/SoftwareCatalogue/ConflictResolver.php` -1. **GIVEN** SoftwareCatalogueService has 7+ class-level suppressions indicating an oversized god-class **WHEN** decomposed **THEN** API communication methods move to `SoftwareCatalogue/ApiClient.php`, data mapping to `SoftwareCatalogue/DataMapper.php`, and conflict resolution to `SoftwareCatalogue/ConflictResolver.php`. +#### Scenario: Existing handler pattern reused -2. **GIVEN** the codebase already has a `SoftwareCatalogue/` subdirectory with handler classes (ContactPersonHandler, OrganizationHandler, HierarchyHandler, GroupHandler) **WHEN** additional extraction follows this pattern **THEN** consistency is maintained and the existing handler injection pattern (constructor DI, delegation from parent service) is reused. +- GIVEN the codebase already has a `SoftwareCatalogue/` subdirectory with handler classes +- WHEN additional extraction follows this pattern +- THEN consistency MUST be maintained +- AND the existing handler injection pattern (constructor DI, delegation from parent service) MUST be reused without modification -3. **GIVEN** SoftwareCatalogueService methods contain progress tracking code interleaved with business logic **WHEN** decomposed **THEN** progress tracking calls are isolated to a ProgressTracker wrapper (which already exists at `lib/Service/ProgressTracker.php`), keeping business methods focused. +#### Scenario: Progress tracking isolated to ProgressTracker + +- GIVEN `SoftwareCatalogueService` methods contain progress tracking code interleaved with business logic +- WHEN decomposed +- THEN progress tracking calls MUST be isolated to the existing `lib/Service/ProgressTracker.php` wrapper +- AND business methods MUST contain no inline progress tracking code ### REQ-DECOMP-005: SettingsService Decomposition -The `lib/Service/SettingsService.php` (23 suppressions) MUST be decomposed. This service manages application configuration persistence with methods that validate, transform, and store multiple configuration sections. The high coupling comes from accessing many configuration keys across different domains. +`lib/Service/SettingsService.php` (23 suppressions) MUST be decomposed. This +service manages application configuration persistence with methods that +validate, transform, and store multiple configuration sections. High coupling +comes from accessing many configuration keys across different domains. -**Scenarios:** +#### Scenario: Domain-scoped settings handlers extracted -1. **GIVEN** SettingsService handles sync settings, module settings, organization settings, and ArchiMate settings in one class **WHEN** decomposed **THEN** each configuration domain gets a dedicated handler: `SyncSettingsHandler`, `ModuleSettingsHandler`, `OrganizationSettingsHandler`, with SettingsService acting as a facade. +- GIVEN `SettingsService` handles sync settings, module settings, organisation settings, and ArchiMate settings in one class +- WHEN decomposed +- THEN `lib/Service/Settings/SyncSettingsHandler.php` MUST be created for sync domain +- AND `lib/Service/Settings/ModuleSettingsHandler.php` MUST be created for module domain +- AND `lib/Service/Settings/OrganizationSettingsHandler.php` MUST be created for organisation domain +- AND `SettingsService` MUST act as a facade delegating to these handlers -2. **GIVEN** methods use deep conditional chains to validate configuration values **WHEN** decomposed **THEN** validation logic is extracted into `validate{Domain}Config()` methods using early returns and guard clauses, reducing CC below 10 per method. +#### Scenario: Validation methods use guard clauses -3. **GIVEN** the class has TooManyMethods suppression **WHEN** handler extraction moves groups of related methods to handlers **THEN** SettingsService retains only delegation methods (under 15 public methods). +- GIVEN methods use deep conditional chains to validate configuration values +- WHEN decomposed +- THEN validation logic MUST be extracted into `validate{Domain}Config()` methods +- AND these methods MUST use early returns and guard clauses +- AND each method MUST have CC<10 -### REQ-DECOMP-006: ArchiMate Services Decomposition +#### Scenario: TooManyMethods resolved -The `lib/Service/ArchiMateService.php` (18 suppressions), `lib/Service/ArchiMateImportService.php` (16 suppressions), and `lib/Service/ArchiMateExportService.php` (16 suppressions) MUST be decomposed. These services handle XML parsing, element-level processing, and relationship mapping with deeply nested loops and conditionals. +- GIVEN the class has a `TooManyMethods` suppression +- WHEN handler extraction moves groups of related methods to handlers +- THEN `SettingsService` MUST retain only delegation methods +- AND the public method count MUST be under 15 -**Scenarios:** +### REQ-DECOMP-006: ArchiMate Services Decomposition -1. **GIVEN** ArchiMateImportService has methods that parse XML elements with nested switch statements for element types **WHEN** decomposed **THEN** each element type handler is extracted into a dedicated method (`importElement()`, `importRelationship()`, `importView()`, `importDiagram()`), each under 50 lines. +`lib/Service/ArchiMateService.php` (18 suppressions), +`lib/Service/ArchiMateImportService.php` (16 suppressions), and +`lib/Service/ArchiMateExportService.php` (16 suppressions) MUST be decomposed. +These services handle XML parsing, element-level processing, and relationship +mapping with deeply nested loops and conditionals. -2. **GIVEN** ArchiMateExportService builds XML with deep conditional nesting for attribute handling **WHEN** decomposed **THEN** attribute builders are extracted into `buildElementAttributes()`, `buildRelationshipAttributes()`, and `buildViewAttributes()` helper methods. +#### Scenario: ArchiMateImportService element handlers extracted -3. **GIVEN** ArchiMateService coordinates import and export with 7 class-level suppressions **WHEN** decomposed **THEN** orchestration logic is simplified by delegating to the import/export services (which themselves are now cleaner), and validation logic is extracted into `validateArchiMateFile()`. +- GIVEN `ArchiMateImportService` has methods that parse XML elements with nested switch statements for element types +- WHEN decomposed +- THEN each element type MUST be handled by a dedicated private method: `importElement()`, `importRelationship()`, `importView()`, `importDiagram()` +- AND each extracted method MUST be under 50 lines -4. **GIVEN** all three services have CouplingBetweenObjects suppressions **WHEN** shared dependencies are grouped **THEN** a `ArchiMateContext` value object carries shared state (ObjectService, SettingsService, logger) reducing constructor parameter counts. +#### Scenario: ArchiMateExportService attribute builders extracted -### REQ-DECOMP-007: OrganizationSyncService Decomposition +- GIVEN `ArchiMateExportService` builds XML with deep conditional nesting for attribute handling +- WHEN decomposed +- THEN attribute builders MUST be extracted into `buildElementAttributes()`, `buildRelationshipAttributes()`, and `buildViewAttributes()` helper methods -The `lib/Service/OrganizationSyncService.php` (7 class-level suppressions) MUST be decomposed by extracting sync logic into pipeline stages. The service pulls organization data from external sources with complex mapping, validation, and conflict resolution. +#### Scenario: ArchiMateService orchestration simplified -**Scenarios:** +- GIVEN `ArchiMateService` coordinates import and export with 7 class-level suppressions +- WHEN decomposed +- THEN orchestration logic MUST be simplified by delegating to the import/export services +- AND file validation logic MUST be extracted into `validateArchiMateFile()` -1. **GIVEN** the sync method has >200 execution paths combining fetch, validate, transform, and persist phases **WHEN** decomposed **THEN** each phase becomes a private method: `fetchOrganizations()`, `validateOrganization()`, `transformOrganization()`, `persistOrganization()`, each with NPath <50. +#### Scenario: Shared dependencies grouped into ArchiMateContext -2. **GIVEN** the service handles both create and update flows with shared validation **WHEN** decomposed **THEN** shared validation is extracted into `validateOrganizationData()` called by both `handleCreate()` and `handleUpdate()`. +- GIVEN all three services have `CouplingBetweenObjects` suppressions +- WHEN shared dependencies are grouped +- THEN an `ArchiMate/ArchiMateContext.php` value object MUST carry shared state (ObjectService, SettingsService, logger) +- AND constructor parameter counts for all three services MUST drop below 13 -3. **GIVEN** error handling is scattered throughout the sync method **WHEN** decomposed **THEN** error handling is centralized into `handleSyncError()` with consistent error logging and progress tracking. +### REQ-DECOMP-007: OrganizationSyncService Decomposition -### REQ-DECOMP-008: ContactpersoonService Decomposition +`lib/Service/OrganizationSyncService.php` (7 suppressions) MUST be decomposed +by extracting sync logic into pipeline stages. The service pulls organisation +data from external sources with complex mapping, validation, and conflict +resolution. -The `lib/Service/ContactpersoonService.php` (6 class-level suppressions) MUST be decomposed by extracting validation, enrichment, and persistence phases from the main business methods. +#### Scenario: Sync method decomposed into pipeline stages -**Scenarios:** +- GIVEN the sync method has >200 execution paths combining fetch, validate, transform, and persist phases +- WHEN decomposed +- THEN each phase MUST become a private method: `fetchOrganizations()`, `validateOrganization()`, `transformOrganization()`, `persistOrganization()` +- AND each extracted method MUST have NPath<50 -1. **GIVEN** the service has methods exceeding CC>10 due to field-level validation checks **WHEN** decomposed **THEN** field validation is extracted into a `ContactValidator` helper with methods like `validateEmail()`, `validatePhone()`, `validateName()`, reducing CC below 10. +#### Scenario: Shared validation extracted for create and update -2. **GIVEN** data enrichment logic (looking up organization, resolving duplicates) is interleaved with persistence **WHEN** decomposed **THEN** enrichment is extracted into `enrichContactData()` called before `persistContact()`. +- GIVEN the service handles both create and update flows with shared validation +- WHEN decomposed +- THEN shared validation MUST be extracted into `validateOrganizationData()` +- AND both `handleCreate()` and `handleUpdate()` MUST call this shared method -3. **GIVEN** the class has CouplingBetweenObjects suppression **WHEN** dependencies are analyzed **THEN** rarely-used dependencies (email service, export service) are lazy-loaded via ContainerInterface reducing immediate coupling. +#### Scenario: Error handling centralised -### REQ-DECOMP-009: AangebodenGebruikController and Service Decomposition +- GIVEN error handling is scattered throughout the sync method +- WHEN decomposed +- THEN error handling MUST be centralised into `handleSyncError()` +- AND all error paths MUST use consistent error logging and progress tracking -The `lib/Controller/AangebodenGebruikController.php` (6 suppressions) and `lib/Service/AangebodenGebruikService.php` (5 suppressions) MUST be decomposed. The controller's `create()`, `bulkCreate()`, and `updateStatus()` methods exceed complexity thresholds. +### REQ-DECOMP-008: ContactpersoonService Decomposition -**Scenarios:** +`lib/Service/ContactpersoonService.php` (6 suppressions) MUST be decomposed by +extracting validation, enrichment, and persistence phases from the main +business methods. -1. **GIVEN** `bulkCreate()` has ExcessiveMethodLength with batch processing, validation per item, and error aggregation **WHEN** decomposed **THEN** the method delegates to `validateBulkInput()`, `processBulkItem()`, and `aggregateBulkResults()` private methods. +#### Scenario: Field validation extracted into ContactValidator -2. **GIVEN** `updateStatus()` has CC>10 due to status transition validation **WHEN** decomposed **THEN** status transition rules are extracted into a `StatusTransitionValidator` with a transition map, reducing the method to a simple `validate -> transition -> persist` flow. +- GIVEN the service has methods exceeding CC>10 due to field-level validation checks +- WHEN decomposed +- THEN field validation MUST be extracted into a `lib/Service/Contactpersoon/ContactValidator.php` helper +- AND `ContactValidator` MUST expose `validateEmail()`, `validatePhone()`, and `validateName()` methods +- AND each method MUST have CC<10 -3. **GIVEN** the service has 5 class-level suppressions **WHEN** decomposed following the handler pattern **THEN** a `GebruikStatusHandler` and `GebruikBulkHandler` are created, each handling their specific concern. +#### Scenario: Enrichment separated from persistence -### REQ-DECOMP-010: ViewService and SymfonyEmailService Decomposition +- GIVEN data enrichment logic (organisation lookup, duplicate resolution) is interleaved with persistence +- WHEN decomposed +- THEN enrichment MUST be extracted into `enrichContactData()` called before `persistContact()` +- AND these two concerns MUST not be combined in a single method -The `lib/Service/ViewService.php` (5 suppressions) and `lib/Service/SymfonyEmailService.php` (5 suppressions) MUST be decomposed. ViewService manages configurable data views with complex query building. SymfonyEmailService handles email composition with template rendering and attachment handling. +#### Scenario: Rarely-used dependencies lazy-loaded -**Scenarios:** +- GIVEN the class has a `CouplingBetweenObjects` suppression +- WHEN dependencies are analyzed +- THEN rarely-used dependencies (email service, export service) MUST be lazy-loaded via `ContainerInterface` +- AND the constructor parameter count MUST drop below 13 -1. **GIVEN** ViewService has methods that build complex queries with multiple optional filters **WHEN** decomposed **THEN** query building is extracted into a `ViewQueryBuilder` helper with chainable filter methods: `applyDateFilter()`, `applyStatusFilter()`, `applySearchFilter()`, `applySorting()`. +### REQ-DECOMP-009: AangebodenGebruikController and Service Decomposition -2. **GIVEN** SymfonyEmailService composes emails with conditional template selection, attachment handling, and recipient resolution **WHEN** decomposed **THEN** email building is split into `resolveRecipients()`, `renderTemplate()`, `attachFiles()`, and `sendEmail()` methods. +`lib/Controller/AangebodenGebruikController.php` (6 suppressions) and +`lib/Service/AangebodenGebruikService.php` (5 suppressions) MUST be decomposed. +The controller's `create()`, `bulkCreate()`, and `updateStatus()` methods +exceed complexity thresholds. -3. **GIVEN** both services have CyclomaticComplexity and NPathComplexity suppressions **WHEN** decomposed with early returns and guard clauses **THEN** each method has CC<10 and NPath<200 without needing suppressions. +#### Scenario: bulkCreate() decomposed into validate/process/aggregate -### REQ-DECOMP-011: Priority 2 File Decomposition +- GIVEN `bulkCreate()` has ExcessiveMethodLength with batch processing, per-item validation, and error aggregation +- WHEN decomposed +- THEN the method MUST delegate to `validateBulkInput()`, `processBulkItem()`, and `aggregateBulkResults()` private methods +- AND the public `bulkCreate()` method body MUST be ≤20 lines -The 8 files with 3-4 suppressions each (OrganizationHandler, ModuleComplianceService, AanbodService, UserProfileUpdatedEventListener, HierarchyHandler, ModuleRegistrationService, GebruikSyncService, OpenRegisterEventsDebugListener) MUST be decomposed to reduce their complexity below PHPMD thresholds. +#### Scenario: updateStatus() complexity reduced via StatusTransitionValidator -**Scenarios:** +- GIVEN `updateStatus()` has CC>10 due to status transition validation +- WHEN decomposed +- THEN status transition rules MUST be extracted into a `lib/Service/AangebodenGebruik/StatusTransitionValidator.php` class with a transition map +- AND the method MUST reduce to a simple `validate → transition → persist` flow with CC<5 -1. **GIVEN** ModuleComplianceService has 4 suppressions (class complexity, CC, NPath, method length) **WHEN** decomposed **THEN** compliance check logic is split into individual rule evaluators: `checkLicenseCompliance()`, `checkSecurityCompliance()`, `checkDocumentationCompliance()`, each returning a compliance result object. +#### Scenario: Service decomposed into domain handlers -2. **GIVEN** UserProfileUpdatedEventListener has 4 suppressions across 2 methods **WHEN** decomposed **THEN** profile field mapping is extracted into a `ProfileFieldMapper` helper, and the event handling methods delegate to it. +- GIVEN the service has 5 class-level suppressions +- WHEN decomposed following the handler pattern +- THEN `lib/Service/AangebodenGebruik/GebruikStatusHandler.php` MUST be created for status concerns +- AND `lib/Service/AangebodenGebruik/GebruikBulkHandler.php` MUST be created for bulk concerns -3. **GIVEN** HierarchyHandler has 3 suppressions for tree traversal complexity **WHEN** decomposed **THEN** tree operations are extracted into `buildHierarchyTree()`, `resolveParent()`, and `updateChildReferences()` methods. +### REQ-DECOMP-010: ViewService and SymfonyEmailService Decomposition -4. **GIVEN** all 8 files are decomposed **WHEN** the combined suppression count is checked **THEN** the total is reduced from approximately 28 to 0, contributing to the overall 145-suppression elimination goal. +`lib/Service/ViewService.php` (5 suppressions) and +`lib/Service/SymfonyEmailService.php` (5 suppressions) MUST be decomposed. +ViewService manages configurable data views with complex query building. +SymfonyEmailService handles email composition with template rendering and +attachment handling. -### REQ-DECOMP-012: Priority 3 File Cleanup +#### Scenario: ViewService query building extracted into ViewQueryBuilder -The 6 files with 1-2 suppressions each (ModuleComplianceSubscriber, GebruikController, Application, GroupHandler, ModuleVersionService, ViewController) MUST be decomposed or refactored to remove remaining suppressions. +- GIVEN `ViewService` has methods that build complex queries with multiple optional filters +- WHEN decomposed +- THEN query building MUST be extracted into a `lib/Service/ViewQueryBuilder.php` helper +- AND it MUST expose chainable filter methods: `applyDateFilter()`, `applyStatusFilter()`, `applySearchFilter()`, `applySorting()` -**Scenarios:** +#### Scenario: SymfonyEmailService split into composition phases -1. **GIVEN** Application.php has CouplingBetweenObjects + ExcessiveMethodLength **WHEN** decomposed **THEN** event listener registration is extracted into a `EventRegistrar` helper, and service registration into `ServiceRegistrar`, reducing the boot method size. +- GIVEN `SymfonyEmailService` composes emails with conditional template selection, attachment handling, and recipient resolution +- WHEN decomposed +- THEN email building MUST be split into `resolveRecipients()`, `renderTemplate()`, `attachFiles()`, and `sendEmail()` private methods -2. **GIVEN** ModuleVersionService has a single ExcessiveMethodLength **WHEN** decomposed **THEN** the long method is split into `fetchVersionData()`, `compareVersions()`, and `updateVersionRecord()` phases. +#### Scenario: All methods pass CC and NPath thresholds after decomposition -3. **GIVEN** all 6 files are cleaned up **WHEN** `composer check:strict` runs **THEN** zero PHPMD violations remain across the entire codebase for the targeted suppression categories. +- GIVEN both services have `CyclomaticComplexity` and `NPathComplexity` suppressions +- WHEN decomposed with early returns and guard clauses +- THEN each method MUST have CC<10 and NPath<200 +- AND no `@SuppressWarnings(PHPMD.*)` annotations MUST remain in either file -## Decomposition Strategy +### REQ-DECOMP-011: Priority 2 File Decomposition -### For CyclomaticComplexity (>10 branches) -Extract conditional branches into private helper methods: -- Guard clauses: Extract early-return validation into `validate{Thing}()` methods -- Switch-like logic: Extract case handlers into `handle{Case}()` methods -- Nested conditions: Flatten by extracting inner blocks into descriptive methods +The 8 files with 3–4 suppressions each MUST be decomposed to reduce complexity +below PHPMD thresholds. -### For NPathComplexity (>200 paths) -Reduce execution paths by: -- Breaking method into pipeline stages (each stage = private method) -- Extracting independent conditional blocks into separate methods -- Using early returns to eliminate nested paths +#### Scenario: ModuleComplianceService rules split into evaluators -### For ExcessiveMethodLength (>100 lines) -Split long methods into logical phases: -- Validation phase -> `validate{Input}()` -- Preparation phase -> `prepare{Data}()` -- Processing phase -> `process{Thing}()` -- Response phase -> `build{Response}()` +- GIVEN `ModuleComplianceService` has 4 suppressions (class complexity, CC, NPath, method length) +- WHEN decomposed +- THEN compliance check logic MUST be split into individual rule evaluators: `checkLicenseCompliance()`, `checkSecurityCompliance()`, `checkDocumentationCompliance()` +- AND each evaluator MUST return a compliance result object -### For ExcessiveClassComplexity / ExcessiveClassLength -Extract method groups into Handler classes (existing pattern in codebase): -- Create `{ClassName}/{HandlerName}Handler.php` -- Move related methods to the handler -- Inject handler via constructor -- Delegate from original methods (keep public API stable) +#### Scenario: UserProfileUpdatedEventListener delegates to ProfileFieldMapper -### For CouplingBetweenObjects (>13 dependencies) -Reduce constructor parameters by: -- Grouping related dependencies into a single service -- Using lazy loading for rarely-used dependencies (ContainerInterface->get()) -- Moving methods that use specific deps to handler classes +- GIVEN `UserProfileUpdatedEventListener` has 4 suppressions across 2 methods +- WHEN decomposed +- THEN profile field mapping MUST be extracted into a `lib/Service/ProfileFieldMapper.php` helper +- AND the event handling methods MUST delegate to it -## Files Requiring Decomposition +#### Scenario: HierarchyHandler tree operations extracted -### Priority 1 -- Highest complexity (files with 5+ suppressions) +- GIVEN `HierarchyHandler` has 3 suppressions for tree traversal complexity +- WHEN decomposed +- THEN tree operations MUST be extracted into `buildHierarchyTree()`, `resolveParent()`, and `updateChildReferences()` private methods -**lib/Controller/SettingsController.php** (23 suppressions) -Admin settings controller managing synchronization settings, module registration, and catalogue configuration. Class-level suppressions for class length, TooManyMethods, class complexity, and coupling. Method-level suppressions on `syncSoftwareCatalogue`, `registerModules`, `syncOrganizations`, and `configureArchiMate`. +#### Scenario: All 8 Priority 2 files clean -**lib/Service/SettingsService.php** (23 suppressions) -Settings persistence service managing application configuration across multiple domains. +- GIVEN all 8 Priority 2 files are decomposed +- WHEN the combined suppression count is checked +- THEN the total MUST be reduced from approximately 28 to 0 +- AND no new PHPMD violations MUST be introduced -**lib/Service/SoftwareCatalogueService.php** (20 suppressions) -Core service for synchronizing with the VNG Software Catalogus API. +### REQ-DECOMP-012: Priority 3 File Cleanup -**lib/Service/ArchiMateService.php** (18 suppressions) -ArchiMate enterprise architecture model import/export orchestrator. +The 6 files with 1–2 suppressions each MUST be decomposed or refactored to +remove remaining suppressions. -**lib/Service/ArchiMateImportService.php** (16 suppressions) -ArchiMate XML import service parsing Open Exchange Format files. +#### Scenario: Application.php boot method reduced -**lib/Service/ArchiMateExportService.php** (16 suppressions) -ArchiMate XML export service generating Open Exchange Format files. +- GIVEN `Application.php` has `CouplingBetweenObjects` + `ExcessiveMethodLength` +- WHEN decomposed +- THEN event listener registration MUST be extracted into a `lib/Service/EventRegistrar.php` helper +- AND service registration MUST be extracted into `lib/Service/ServiceRegistrar.php` +- AND the boot method size MUST drop below 100 lines -**lib/EventListener/SoftwareCatalogEventListener.php** (11 suppressions) -Event listener handling OpenRegister object events for software catalog synchronization. +#### Scenario: ModuleVersionService long method split -**lib/Controller/ContactpersonenController.php** (11 suppressions) -Contact persons CRUD controller with complex create/update logic. +- GIVEN `ModuleVersionService` has a single `ExcessiveMethodLength` suppression +- WHEN decomposed +- THEN the long method MUST be split into `fetchVersionData()`, `compareVersions()`, and `updateVersionRecord()` phases -**lib/Service/SoftwareCatalogue/ContactPersonHandler.php** (7 suppressions) -Handler for contact person synchronization with the Software Catalogus. +#### Scenario: Final check:strict passes with zero violations -**lib/Service/OrganizationSyncService.php** (7 suppressions) -Organisation synchronization service pulling data from external sources. +- GIVEN all 6 Priority 3 files are cleaned up +- WHEN `composer check:strict` runs +- THEN zero PHPMD violations MUST remain across the entire codebase for the targeted suppression categories +- AND total `@SuppressWarnings(PHPMD.*)` annotations in `lib/` MUST be reduced by at least 145 -**lib/Service/ContactpersoonService.php** (6 suppressions) -Contact person business logic service. +## Non-functional Requirements -**lib/Controller/AangebodenGebruikController.php** (6 suppressions) -"Offered usage" (software deployments) controller. +### REQ-DECOMP-NFR-001: No behavioral changes -**lib/Service/ViewService.php** (5 suppressions) -View/dashboard service managing configurable data views. +- GIVEN any decomposed method or class +- WHEN tests run before and after the decomposition +- THEN test outcomes MUST be identical +- AND no observable behavior (API response shape, database writes, event dispatching) MUST change -**lib/Service/SymfonyEmailService.php** (5 suppressions) -Email sending service using Symfony Mailer. +### REQ-DECOMP-NFR-002: @spec traceability -**lib/Service/AangebodenGebruikService.php** (5 suppressions) -Software usage/deployment business logic. +- GIVEN any new class or public method introduced by this change +- WHEN its PHPDoc block is read +- THEN it MUST include at least one `@spec openspec/changes/method-decomposition/tasks.md#task-N` tag per ADR-003 -### Priority 2 -- Medium complexity (files with 3-4 suppressions) +### REQ-DECOMP-NFR-003: SPDX headers on new files -- `lib/Service/SoftwareCatalogue/OrganizationHandler.php` (4) -- `lib/Service/ModuleComplianceService.php` (4) -- `lib/Service/AanbodService.php` (4) -- `lib/EventListener/UserProfileUpdatedEventListener.php` (4) -- `lib/Service/SoftwareCatalogue/HierarchyHandler.php` (3) -- `lib/Service/ModuleRegistrationService.php` (3) -- `lib/Service/GebruikSyncService.php` (3) -- `lib/EventListener/OpenRegisterEventsDebugListener.php` (3) +- GIVEN any new PHP file created by this change +- WHEN its contents are read +- THEN the second line (after `&1 | wc -l` - -### During decomposition (per method) -1. Verify `php -l` passes on all changed files -2. Run unit tests for the specific class: `--filter ClassName` -3. Run PHPMD on the specific file to confirm suppression can be removed - -### After decomposition -1. Full unit test suite passes -2. PHPMD reports 0 violations (no new warnings) -3. Total suppression count reduced by expected amount -4. `composer check:strict` passes -5. Manual smoke test in browser (http://localhost:3000) - -## Acceptance Criteria -- [ ] All CyclomaticComplexity suppressions eliminated or reduced to <=5 -- [ ] All NPathComplexity suppressions eliminated or reduced to <=5 -- [ ] All ExcessiveMethodLength suppressions eliminated or reduced to <=5 -- [ ] ExcessiveClassComplexity reduced by extracting handler classes -- [ ] CouplingBetweenObjects reduced by dependency grouping and handler extraction -- [ ] TooManyMethods reduced by handler extraction -- [ ] No new PHPMD violations introduced -- [ ] All existing tests continue to pass -- [ ] No behavioral changes (pure refactoring) -- [ ] `composer check:strict` passes with zero violations +- GIVEN a developer wants to verify a decomposed class +- WHEN they run unit tests +- THEN they MUST invoke PHPUnit via: + `docker exec -w /var/www/html/custom_apps/softwarecatalog nextcloud php vendor/bin/phpunit -c phpunit-unit.xml` +- AND class-scoped filtering MUST be available via `--filter ClassName` per ADR-008 diff --git a/openspec/changes/method-decomposition/tasks.md b/openspec/changes/method-decomposition/tasks.md index 5d3ef4ab..39ac4bf7 100644 --- a/openspec/changes/method-decomposition/tasks.md +++ b/openspec/changes/method-decomposition/tasks.md @@ -1,15 +1,261 @@ -# Tasks: Method Decomposition +# Tasks — method-decomposition -## Task 1: SettingsController Decomposition -- [ ] Extract SyncHandler -- [ ] Extract ModuleRegistrationHandler -- [ ] Reduce constructor dependencies +> Spec-only companion tasks. This change is a pure PHP refactoring; no new +> OpenRegister schemas, no frontend changes, no new public API. -## Task 2: Service Decomposition -- [ ] Decompose ArchimateService -- [ ] Decompose EnrichService -- [ ] Decompose GemmaService +## Phase 0 — Deduplication check + baseline -## Task 3: Cleanup -- [ ] Remove all PHPMD suppressions from decomposed classes -- [ ] Run composer check:strict to verify +- [ ] 0.1 Verify no new capability duplicates existing OpenRegister services: + - Search `openregister/lib/Service/` and `openspec/specs/` for ObjectService, + RegisterService, SchemaService, ConfigurationService equivalents + - Document findings in `design.md` Reuse Analysis table (even if "no overlap found") +- [ ] 0.2 Capture current PHPMD suppression baseline: + - Run: `docker exec -w /var/www/html/custom_apps/softwarecatalog nextcloud ./vendor/bin/phpmd lib/ text phpmd.xml 2>&1 | grep -c SuppressWarnings` + - Record count in PR description (expected: ≥145 in targeted categories) +- [ ] 0.3 Capture PHPUnit baseline: + - Run: `docker exec -w /var/www/html/custom_apps/softwarecatalog nextcloud php vendor/bin/phpunit -c phpunit-unit.xml` + - Record any pre-existing failures so they are not attributed to this change +- [ ] 0.4 Verify `composer check:strict` script exists and runs PHPMD, PHPCS, + Psalm/PHPStan. If missing, do NOT create it — raise with maintainer. + +## Phase 1 — SettingsService decomposition (REQ-DECOMP-005) + +Decompose first — downstream handlers (ArchiMateContext, SyncHandler) depend on +its post-refactor facade. + +- [ ] 1.1 Audit `lib/Service/SettingsService.php`: + - List all public methods and group by domain: sync, modules, organisations, ArchiMate + - Identify which methods have CC>10 or >100 lines +- [ ] 1.2 Create `lib/Service/Settings/SyncSettingsHandler.php`: + - SPDX header: `// SPDX-License-Identifier: EUPL-1.2` + - `@spec openspec/changes/method-decomposition/tasks.md#task-1` + - Move sync-domain methods; extract `validateSyncConfig()` guard clauses +- [ ] 1.3 Create `lib/Service/Settings/ModuleSettingsHandler.php`: + - Same SPDX + `@spec` requirements + - Move module-domain methods; extract `validateModuleConfig()` +- [ ] 1.4 Create `lib/Service/Settings/OrganizationSettingsHandler.php`: + - Move organisation-domain methods; extract `validateOrganizationConfig()` +- [ ] 1.5 Refactor `SettingsService` to facade pattern: + - Inject all three handlers via constructor + - Replace method bodies with single-line delegation calls + - Verify public method count ≤15 +- [ ] 1.6 Remove all `@SuppressWarnings(PHPMD.*)` from `SettingsService.php` +- [ ] 1.7 Run `./vendor/bin/phpmd lib/Service/Settings/ text phpmd.xml` — must be zero violations +- [ ] 1.8 Run `phpunit --filter SettingsServiceTest` — must pass + +## Phase 2 — SoftwareCatalogueService decomposition (REQ-DECOMP-004) + +- [ ] 2.1 Audit `lib/Service/SoftwareCatalogueService.php`: + - Identify API communication, data mapping, and conflict resolution method groups + - Map which methods call `ProgressTracker` — these must be isolated +- [ ] 2.2 Create `lib/Service/SoftwareCatalogue/ApiClient.php`: + - SPDX header + `@spec openspec/changes/method-decomposition/tasks.md#task-2` + - Move all API communication methods (HTTP calls, response parsing) +- [ ] 2.3 Create `lib/Service/SoftwareCatalogue/DataMapper.php`: + - Move all data mapping / transformation methods +- [ ] 2.4 Create `lib/Service/SoftwareCatalogue/ConflictResolver.php`: + - Move all conflict resolution / deduplication methods +- [ ] 2.5 Isolate progress tracking: + - Remove all inline `ProgressTracker` calls from business methods + - Ensure `ProgressTracker` is only called at the orchestration level in the parent service +- [ ] 2.6 Update `SoftwareCatalogueService` to inject new sub-services and delegate +- [ ] 2.7 Remove all `@SuppressWarnings(PHPMD.*)` from `SoftwareCatalogueService.php` +- [ ] 2.8 Run PHPMD on all affected files — zero violations +- [ ] 2.9 Run `phpunit --filter SoftwareCatalogueServiceTest` — must pass + +## Phase 3 — SettingsController decomposition (REQ-DECOMP-001) + +Depends on Phase 1 (SettingsService facade must exist). + +- [ ] 3.1 Create `lib/Controller/Settings/SyncHandler.php`: + - SPDX header + `@spec openspec/changes/method-decomposition/tasks.md#task-3` + - Inject only `ObjectService` and `SoftwareCatalogueService` + - Expose `handle(array $config): array` public method + - Extract private: `validateSyncConfig()`, `prepareSyncData()`, `executeSyncBatch()`, `buildSyncResponse()` +- [ ] 3.2 Create `lib/Controller/Settings/ModuleRegistrationHandler.php`: + - Inject only `ObjectService` and `ModuleRegistrationService` + - Extract private: `validateModuleInput()`, `resolveModuleDependencies()`, `persistModules()` +- [ ] 3.3 Refactor `SettingsController`: + - Replace `syncSoftwareCatalogue()` body with `$this->syncHandler->handle(...)` + - Replace `registerModules()` body with `$this->moduleHandler->handle(...)` + - Verify each action method is ≤10 lines per ADR-003 + - Verify constructor parameter count <13 +- [ ] 3.4 Remove all `@SuppressWarnings(PHPMD.*)` from `SettingsController.php` +- [ ] 3.5 Run PHPMD on controller + new handler files — zero violations +- [ ] 3.6 Run `phpunit --filter SettingsControllerTest` — must pass + +## Phase 4 — ArchiMate services decomposition (REQ-DECOMP-006) + +Depends on Phase 1 (SettingsService facade used in ArchiMateContext). + +- [ ] 4.1 Create `lib/Service/ArchiMate/ArchiMateContext.php`: + - SPDX header + `@spec openspec/changes/method-decomposition/tasks.md#task-4` + - Constructor: `ObjectService $objectService`, `SettingsService $settingsService`, `LoggerInterface $logger` + - Public readonly properties for each +- [ ] 4.2 Decompose `lib/Service/ArchiMateImportService.php`: + - Extract `importElement()`, `importRelationship()`, `importView()`, `importDiagram()` — each ≤50 lines + - Inject `ArchiMateContext` to reduce constructor coupling + - Remove all `@SuppressWarnings(PHPMD.*)` +- [ ] 4.3 Decompose `lib/Service/ArchiMateExportService.php`: + - Extract `buildElementAttributes()`, `buildRelationshipAttributes()`, `buildViewAttributes()` + - Inject `ArchiMateContext` + - Remove all `@SuppressWarnings(PHPMD.*)` +- [ ] 4.4 Decompose `lib/Service/ArchiMateService.php`: + - Simplify orchestration — delegate to import/export services + - Extract `validateArchiMateFile()` with guard clauses + - Inject `ArchiMateContext` + - Remove all `@SuppressWarnings(PHPMD.*)` +- [ ] 4.5 Run PHPMD on all three ArchiMate service files — zero violations +- [ ] 4.6 Run `phpunit --filter ArchiMate` — must pass + +## Phase 5 — ContactpersonenController decomposition (REQ-DECOMP-003) + +- [ ] 5.1 Extract `validateContactInput(array $data): array` private method from `create()` +- [ ] 5.2 Extract `enrichContactData(array $data): array` private method from `create()` +- [ ] 5.3 Extract `persistContact(array $data): JSONResponse` private method from `create()` +- [ ] 5.4 Decompose `bulkImport()`: + - Extract `parseImportFile()`, `validateImportRow()`, `processImportBatch()`, `buildImportReport()` +- [ ] 5.5 Decompose `exportContacts()`: + - Extract `buildExportQuery()`, `formatExportData()`, `buildExportResponse()` +- [ ] 5.6 Verify class drops below 1000 lines and coupling below 13 +- [ ] 5.7 Remove all `@SuppressWarnings(PHPMD.*)` from `ContactpersonenController.php` +- [ ] 5.8 Run PHPMD — zero violations; run `phpunit --filter ContactpersonenControllerTest` — must pass + +## Phase 6 — SoftwareCatalogEventListener decomposition (REQ-DECOMP-002) + +- [ ] 6.1 Create `lib/Service/ModuleEventProcessor.php`: + - SPDX header + `@spec openspec/changes/method-decomposition/tasks.md#task-6` + - Extract shared 60% logic from `handleModuleCreated` and `handleModuleUpdated` +- [ ] 6.2 Decompose `handleModuleCreated()`: + - Extract `validateModuleEvent()` with guard clauses (early-return validation) + - Extract `processModuleByType()` for type-specific logic + - Extract `mapModuleToSchema()` for schema mapping +- [ ] 6.3 Decompose `handleModuleUpdated()` to delegate to `ModuleEventProcessor` +- [ ] 6.4 Decompose `handleOrganizationEvent()`: + - Extract `handleOrganizationCreate()`, `handleOrganizationUpdate()`, `handleOrganizationDelete()` + - Each extracted method MUST have NPath<50 +- [ ] 6.5 Remove all `@SuppressWarnings(PHPMD.*)` from event listener +- [ ] 6.6 Run PHPMD — zero violations; run `phpunit --filter SoftwareCatalogEventListenerTest` — must pass + +## Phase 7 — Remaining Priority 1 files (REQ-DECOMP-007, 008, 009, 010) + +- [ ] 7.1 **OrganizationSyncService** (REQ-DECOMP-007): + - Extract pipeline stages: `fetchOrganizations()`, `validateOrganization()`, `transformOrganization()`, `persistOrganization()` each with NPath<50 + - Extract shared `validateOrganizationData()` called by both `handleCreate()` and `handleUpdate()` + - Centralise error handling into `handleSyncError()` + - Remove all suppressions; run PHPMD + phpunit +- [ ] 7.2 **ContactpersoonService** (REQ-DECOMP-008): + - Create `lib/Service/Contactpersoon/ContactValidator.php` with `validateEmail()`, `validatePhone()`, `validateName()` + - Extract `enrichContactData()` before `persistContact()` + - Lazy-load email service + export service via `ContainerInterface` + - Remove all suppressions; run PHPMD + phpunit +- [ ] 7.3 **AangebodenGebruikController + Service** (REQ-DECOMP-009): + - Create `lib/Service/AangebodenGebruik/StatusTransitionValidator.php` with transition map + - Create `lib/Service/AangebodenGebruik/GebruikStatusHandler.php` + - Create `lib/Service/AangebodenGebruik/GebruikBulkHandler.php` + - Decompose `bulkCreate()` into `validateBulkInput()`, `processBulkItem()`, `aggregateBulkResults()` + - Reduce `updateStatus()` to `validate → transition → persist` with CC<5 + - Remove all suppressions; run PHPMD + phpunit +- [ ] 7.4 **ViewService** (REQ-DECOMP-010): + - Create `lib/Service/ViewQueryBuilder.php` with `applyDateFilter()`, `applyStatusFilter()`, `applySearchFilter()`, `applySorting()` + - Remove all suppressions; run PHPMD + phpunit +- [ ] 7.5 **SymfonyEmailService** (REQ-DECOMP-010): + - Extract `resolveRecipients()`, `renderTemplate()`, `attachFiles()`, `sendEmail()` private methods + - Remove all suppressions; run PHPMD + phpunit +- [ ] 7.6 **SoftwareCatalogue/ContactPersonHandler** (Priority 1, 7 suppressions): + - Private method decomposition — extract per-phase methods + - Remove all suppressions; run PHPMD + phpunit + +## Phase 8 — Priority 2 files (REQ-DECOMP-011) + +- [ ] 8.1 **SoftwareCatalogue/OrganizationHandler** (4 suppressions): + - Private method extraction for complex methods + - Remove suppressions; run PHPMD +- [ ] 8.2 **ModuleComplianceService** (4 suppressions): + - Extract `checkLicenseCompliance()`, `checkSecurityCompliance()`, `checkDocumentationCompliance()` + - Each returns a compliance result object + - Remove suppressions; run PHPMD +- [ ] 8.3 **AanbodService** (4 suppressions): + - Audit and apply private method extraction per decomposition strategy + - Remove suppressions; run PHPMD +- [ ] 8.4 **UserProfileUpdatedEventListener** (4 suppressions): + - Create `lib/Service/ProfileFieldMapper.php` + - Event handling methods delegate to `ProfileFieldMapper` + - Remove suppressions; run PHPMD +- [ ] 8.5 **SoftwareCatalogue/HierarchyHandler** (3 suppressions): + - Extract `buildHierarchyTree()`, `resolveParent()`, `updateChildReferences()` + - Remove suppressions; run PHPMD +- [ ] 8.6 **ModuleRegistrationService** (3 suppressions): + - Private method extraction; remove suppressions; run PHPMD +- [ ] 8.7 **GebruikSyncService** (3 suppressions): + - Private method extraction; remove suppressions; run PHPMD +- [ ] 8.8 **OpenRegisterEventsDebugListener** (3 suppressions): + - Private method extraction; remove suppressions; run PHPMD + +## Phase 9 — Priority 3 files (REQ-DECOMP-012) + +- [ ] 9.1 **Application.php** (2 suppressions): + - Create `lib/Service/EventRegistrar.php` — extract event listener registration + - Create `lib/Service/ServiceRegistrar.php` — extract service registration + - Boot method MUST drop below 100 lines + - Remove suppressions; run PHPMD +- [ ] 9.2 **ModuleComplianceSubscriber** (2 suppressions): + - Private method extraction; remove suppressions; run PHPMD +- [ ] 9.3 **GebruikController** (2 suppressions): + - Private method extraction; thin controller per ADR-003; remove suppressions +- [ ] 9.4 **SoftwareCatalogue/GroupHandler** (1 suppression): + - Extract the single oversized method; remove suppression +- [ ] 9.5 **ModuleVersionService** (1 suppression): + - Split the long method into `fetchVersionData()`, `compareVersions()`, `updateVersionRecord()` + - Remove suppression +- [ ] 9.6 **ViewController** (1 suppression): + - Extract oversized method; remove suppression + +## Phase 10 — Verification + +- [ ] 10.1 Run full PHPUnit suite: + ``` + docker exec -w /var/www/html/custom_apps/softwarecatalog nextcloud \ + php vendor/bin/phpunit -c phpunit-unit.xml + ``` + All tests MUST pass. Failures not pre-existing in Phase 0 baseline MUST be fixed. +- [ ] 10.2 Run PHPMD across entire `lib/`: + ``` + docker exec -w /var/www/html/custom_apps/softwarecatalog nextcloud \ + ./vendor/bin/phpmd lib/ text phpmd.xml 2>&1 + ``` + Zero violations MUST be reported for targeted suppression categories. +- [ ] 10.3 Run `composer check:strict` — exit code MUST be 0, zero new warnings +- [ ] 10.4 Count remaining `@SuppressWarnings(PHPMD.*)` in `lib/`: + ``` + grep -rc '@SuppressWarnings(PHPMD' lib/ | awk -F: '{sum+=$2} END{print sum}' + ``` + The count MUST be reduced by at least 145 from the Phase 0 baseline. +- [ ] 10.5 Manual smoke test: navigate http://localhost:3000, verify settings, + sync, and contact person workflows behave identically to pre-refactor. +- [ ] 10.6 Verify all new PHP files have SPDX headers: + ``` + grep -rL 'SPDX-License-Identifier' lib/ --include='*.php' + ``` + Output MUST be empty. +- [ ] 10.7 Verify all new classes and public methods have `@spec` PHPDoc tags: + - Spot-check at least 5 new handler classes + - Each MUST have `@spec openspec/changes/method-decomposition/tasks.md#task-N` +- [ ] 10.8 Pre-commit checklist (ADR-015): + - [ ] No `$e->getMessage()` in JSONResponse — use static error strings + - [ ] All POST/PUT/DELETE controller methods have `IGroupManager::isAdmin()` check + - [ ] No `\OC::$server` static locators in new handler classes + +## Acceptance Criteria + +- [ ] All CyclomaticComplexity suppressions eliminated (target: reduced to 0 in decomposed files) +- [ ] All NPathComplexity suppressions eliminated +- [ ] All ExcessiveMethodLength suppressions eliminated +- [ ] ExcessiveClassComplexity removed by handler extraction +- [ ] CouplingBetweenObjects removed by handler extraction and lazy-loading +- [ ] TooManyMethods removed by handler extraction +- [ ] No new PHPMD violations introduced in any file +- [ ] All existing tests continue to pass +- [ ] No behavioral changes (pure refactoring — public API unchanged) +- [ ] `composer check:strict` passes with zero violations +- [ ] Total suppression count in `lib/` reduced by ≥145 From 9710919865cca68964e312bcb5c95df4a228c9ad Mon Sep 17 00:00:00 2001 From: Specter Intelligence Date: Wed, 20 May 2026 11:02:58 +0200 Subject: [PATCH 008/662] feat: Add OpenSpec change method-decomposition from Specter --- .../architecture/adr-001-data-layer.md | 223 +++++++++++ .claude/openspec/architecture/adr-002-api.md | 6 + .../openspec/architecture/adr-003-backend.md | 14 + .../openspec/architecture/adr-004-frontend.md | 255 +++++++++++++ .../openspec/architecture/adr-005-security.md | 42 +++ .../openspec/architecture/adr-006-metrics.md | 3 + .claude/openspec/architecture/adr-007-i18n.md | 57 +++ .../openspec/architecture/adr-008-testing.md | 32 ++ .claude/openspec/architecture/adr-009-docs.md | 2 + .../architecture/adr-010-nl-design.md | 8 + .../architecture/adr-011-schema-standards.md | 8 + .../architecture/adr-012-deduplication.md | 7 + .../architecture/adr-013-container-pool.md | 178 +++++++++ .../architecture/adr-014-licensing.md | 62 +++ .../architecture/adr-015-common-patterns.md | 98 +++++ .../openspec/architecture/adr-016-routes.md | 28 ++ .../adr-017-component-composition.md | 86 +++++ .../adr-018-widget-header-actions.md | 105 ++++++ .../adr-019-integration-registry.md | 113 ++++++ .../adr-020-gate-scope-to-pr-diff.md | 61 +++ .../adr-021-bounded-fix-scope-by-shape.md | 76 ++++ .../adr-022-apps-consume-or-abstractions.md | 125 ++++++ .../adr-023-action-authorization.md | 183 +++++++++ .../architecture/adr-024-app-manifest.md | 113 ++++++ .../adr-025-i18n-source-of-truth.md | 157 ++++++++ .../adr-029-route-reachability-gate.md | 163 ++++++++ .../adr-030-journeydoc-pattern.md | 188 +++++++++ ...r-031-schema-declarative-business-logic.md | 357 ++++++++++++++++++ .../adr-032-spec-sizing-and-chaining.md | 293 ++++++++++++++ .specter-prompt.txt | 49 +++ 30 files changed, 3092 insertions(+) create mode 100644 .claude/openspec/architecture/adr-001-data-layer.md create mode 100644 .claude/openspec/architecture/adr-002-api.md create mode 100644 .claude/openspec/architecture/adr-003-backend.md create mode 100644 .claude/openspec/architecture/adr-004-frontend.md create mode 100644 .claude/openspec/architecture/adr-005-security.md create mode 100644 .claude/openspec/architecture/adr-006-metrics.md create mode 100644 .claude/openspec/architecture/adr-007-i18n.md create mode 100644 .claude/openspec/architecture/adr-008-testing.md create mode 100644 .claude/openspec/architecture/adr-009-docs.md create mode 100644 .claude/openspec/architecture/adr-010-nl-design.md create mode 100644 .claude/openspec/architecture/adr-011-schema-standards.md create mode 100644 .claude/openspec/architecture/adr-012-deduplication.md create mode 100644 .claude/openspec/architecture/adr-013-container-pool.md create mode 100644 .claude/openspec/architecture/adr-014-licensing.md create mode 100644 .claude/openspec/architecture/adr-015-common-patterns.md create mode 100644 .claude/openspec/architecture/adr-016-routes.md create mode 100644 .claude/openspec/architecture/adr-017-component-composition.md create mode 100644 .claude/openspec/architecture/adr-018-widget-header-actions.md create mode 100644 .claude/openspec/architecture/adr-019-integration-registry.md create mode 100644 .claude/openspec/architecture/adr-020-gate-scope-to-pr-diff.md create mode 100644 .claude/openspec/architecture/adr-021-bounded-fix-scope-by-shape.md create mode 100644 .claude/openspec/architecture/adr-022-apps-consume-or-abstractions.md create mode 100644 .claude/openspec/architecture/adr-023-action-authorization.md create mode 100644 .claude/openspec/architecture/adr-024-app-manifest.md create mode 100644 .claude/openspec/architecture/adr-025-i18n-source-of-truth.md create mode 100644 .claude/openspec/architecture/adr-029-route-reachability-gate.md create mode 100644 .claude/openspec/architecture/adr-030-journeydoc-pattern.md create mode 100644 .claude/openspec/architecture/adr-031-schema-declarative-business-logic.md create mode 100644 .claude/openspec/architecture/adr-032-spec-sizing-and-chaining.md create mode 100644 .specter-prompt.txt diff --git a/.claude/openspec/architecture/adr-001-data-layer.md b/.claude/openspec/architecture/adr-001-data-layer.md new file mode 100644 index 00000000..7d451b92 --- /dev/null +++ b/.claude/openspec/architecture/adr-001-data-layer.md @@ -0,0 +1,223 @@ +- ALL domain data → OpenRegister objects. NO custom Entity/Mapper for domain data. +- App config → `IAppConfig`. NOT OpenRegister. +- Cross-entity references: OpenRegister relations (register+schema+objectId). NO foreign keys. + MUST NOT store foreign keys or embed full objects. + +### Schema standards + +- Schemas: PascalCase, schema.org vocabulary, explicit types + required flags + description field. +- MUST NOT invent custom property names when a schema.org equivalent exists. +- Contact schemas MUST align with vCard properties (fn, email, tel, adr). +- Dutch government fields SHOULD use a mapping layer translating between international standards + and Dutch specs — do not hardcode Dutch field names as primary. +- Schema changes that remove or rename properties are BREAKING. Adding optional properties is non-breaking. + +### Register templates + +- Location: `lib/Settings/{app}_register.json` (OpenAPI 3.0 + `x-openregister` extensions). +- Three template categories: + - **App configuration** — define data models (schemas/registers/views/mappings). + Mark with `x-openregister.type: "application"`. + - **Mock data** — fictional but realistic seed data for dev/test. + Mark with `x-openregister.type: "mock"`. + - **Government standards** — aligned to Dutch API specs (BAG, BRP, KVK, DSO). +- Import mechanism: `ConfigurationService::importFromApp(appId, data, version, force)` → + `ImportHandler::importFromApp()`. Called from repair step or `SettingsLoadService`. +- Idempotency: re-importing with `force: false` MUST NOT create duplicates. Match by slug + using `ObjectService::searchObjects` with `_rbac: false` and `_multitenancy: false`. + Use `version_compare` for skip logic. + +### Seed data + +Apps that store data in OpenRegister are empty on first install. An empty app cannot be +meaningfully tested — there are no objects to view, search, filter, or interact with. +This blocks both automated browser testing and manual QA. The Loadable Register Template +pattern (see Register templates above) already supports seed data via `components.objects[]` +with the `@self` envelope. + +**Requirements:** + +- Every app using OpenRegister MUST include 3-5 realistic objects per schema in + `lib/Settings/{app}_register.json`. +- Use `@self` envelope: `{ "@self": { "register": ..., "schema": ..., "slug": ... }, ...properties }`. + Register/schema MUST match keys; slug is unique human-readable identifier for matching. +- Use general organisation data (municipality, consultancy, travel agency, non-profit) — + NOT context-specific. Varied, realistic field values. +- Mock data quality: real Dutch street names, valid postcodes (`[1-9][0-9]{3}[A-Z]{2}`), + correct municipality/KVK codes, BSNs that pass 11-proef. Fictional but distinguishable from real. +- Cross-register consistency: BRP→BAG, KVK→BAG, DSO→BAG references must be valid. +- Loaded on install alongside schemas via same `importFromApp()` pipeline. +- MUST be idempotent — re-importing skips existing objects matched by slug. + +**In OpenSpec artifacts:** + +- **In design.md**: MUST include a Seed Data section when change introduces/modifies schemas — + define seed objects per schema with concrete field values and related items (files, notes, tasks, contacts). +- **In tasks.md**: MUST include a seed data generation task when change introduces/modifies schemas. + +**Exceptions** (no seed data required): + +- **nldesign** — has no OpenRegister schemas. +- **ExApp sidecar wrappers** (openklant, opentalk, openzaak, valtimo, n8n-nextcloud) — proxy + external services and do not use OpenRegister. +- **nextcloud-vue** — shared library, no seed data applicable. +- Changes that only modify frontend components or non-schema backend logic (e.g., settings, + permissions) do not require seed data. + +**Limitations:** OpenRegister's `ImportHandler` currently supports only flat seed objects. +Related items (files, notes, tasks, contacts) linked through the relation system are tracked +in OpenRegister's pending `seed-related-items` openspec change (see +`openregister/openspec/changes/seed-related-items/`). Until that lands, seed data is limited +to object properties defined in schemas. + +### Deduplication check + +- Before proposing new capability: search `openspec/specs/` and `openregister/lib/Service/` for overlap + with ObjectService, RegisterService, SchemaService, ConfigurationService, and shared Vue components. +- If similar capability exists: MUST reference it and explain why new code is needed rather than extending. +- Proposals duplicating existing functionality without justification MUST be rejected. +- **In design.md**: MUST include a "Reuse Analysis" section listing existing OpenRegister services leveraged. +- **In tasks.md**: MUST include a "Deduplication Check" task verifying no overlap — document findings + even if "no overlap found". + +### Schema migrations + +- Breaking schema changes → new migration in repair step. NEVER modify existing migrations. + +### OpenRegister + @conduction/nextcloud-vue — DO NOT REBUILD + +The platform provides 258+ backend methods and 69+ frontend components. Apps ONLY build +custom logic for domain-specific business rules. Everything below is provided for FREE. + +**CRUD & Data Management** (use ObjectService + CnIndexPage + CnDetailPage): +- Single & bulk create, read, update, delete — `ObjectService.saveObject()`, `deleteObject()` +- List with pagination, sorting, filtering — `ObjectService.findAll()` + `CnDataTable` +- Schema-driven forms — `CnFormDialog` (auto-generates from schema) or `CnAdvancedFormDialog` +- Detail views — `CnDetailPage` with `CnDetailGrid`, `CnDetailCard` sections +- Record merging/deduplication — `ObjectService.mergeObjects()` +- Object locking — `ObjectService.lockObject()` / `unlockObject()` + +**Import & Export** (use ImportService/ExportService + CnMassImportDialog/CnMassExportDialog): +- CSV, Excel, JSON import with intelligent field mapping — `ImportService` +- CSV, Excel, JSON export with column selection — `ExportService` +- Bulk import with validation and progress — `CnMassImportDialog` +- Filtered export with format picker — `CnMassExportDialog` +- NO custom import dialogs, parsers, upload handlers, or export controllers + +**Search & Discovery** (use IndexService + CnFilterBar + CnFacetSidebar): +- Full-text search with field weighting — `IndexService` +- Faceted navigation with counts — `FacetBuilder` + `CnFacetSidebar` +- Semantic search with embeddings — `VectorizationService` +- Hybrid search (keyword + semantic) — automatic +- Search analytics — `SearchTrailService` (popular terms, activity) +- NO custom search endpoints, query builders, or search pages + +**File Management** (use FileService + CnObjectSidebar): +- Upload (single/multipart), download, share links — `FileService` +- File tagging, public/private toggle — `FileService` +- Bulk download as ZIP — `createObjectFilesZip()` +- Text extraction from PDFs/Office docs — `TextExtractionService` +- File tab in object sidebar — `CnObjectSidebar` → `CnFilesTab` +- NO custom file upload components, file controllers, or download handlers + +**Audit & Compliance** (use AuditTrailService + CnObjectSidebar): +- Full change tracking with before/after snapshots — automatic +- Audit trail tab — `CnObjectSidebar` → `CnAuditTrailTab` +- GDPR data subject access requests — `inzageverzoek()`, `verwerkingsregister()` +- Audit export and analytics — `AuditTrailController` +- NO custom audit logging, change tracking, or compliance controllers + +**Dashboard & Analytics** (use CnDashboardPage + CnChartWidget + CnStatsBlock): +- Drag-drop widget dashboard — `CnDashboardPage` with GridStack +- KPI cards — `CnKpiGrid`, `CnStatsBlock`, `CnStatsPanel` +- Charts (line/bar/pie/donut) — `CnChartWidget` (ApexCharts) +- Data tables as widgets — `CnTableWidget` +- Editable data grids — `CnObjectDataWidget` +- NO custom dashboard layouts, chart components, or KPI cards + +**Forms & Dialogs** (use CnFormDialog + schema-driven generation): +- Auto-generated create/edit forms — `CnFormDialog` reads schema → generates fields +- JSON/metadata editing — `CnAdvancedFormDialog` with Properties/Data/Metadata tabs +- Schema editor — `CnSchemaFormDialog` +- Delete/Copy/Mass operations — `CnDeleteDialog`, `CnCopyDialog`, `CnMassDeleteDialog` +- NO custom form components, validation logic, or dialog wrappers + +**Navigation & Pagination** (use CnPagination + CnActionsBar + useListView): +- Pagination control with size selector — `CnPagination` +- Action bar (add, search, toggle views) — `CnActionsBar` +- List state management — `useListView` composable (handles search, filter, sort, page) +- Detail state management — `useDetailView` composable +- NO custom pagination logic, debounced search, or list state management + +**Authorization & RBAC** (use AuthorizationService + PropertyRbacHandler): +- Role-based access control — `AuthorizationService` +- Field-level permissions — `PropertyRbacHandler` +- Object-level restrictions — `PermissionHandler` +- Authorization audit — `AuthorizationAuditService` +- NO custom permission checks, role systems, or access control middleware + +**Webhooks & Events** (use WebhookService): +- Create, test, retry webhooks — `WebhookService` +- CloudEvents format — automatic +- Event subscriptions — selective per schema/action +- NO custom webhook controllers or event dispatchers + +**Notifications & Activity** (use NotificationService + ActivityService): +- Nextcloud notifications — `NotificationService` +- Activity feed — `ActivityService` +- Calendar events — `CalendarEventService` +- Deck/Kanban cards — `DeckCardService` + +**Store & State** (use createObjectStore + plugins): +- Object stores — `createObjectStore(name)` generates Pinia CRUD store +- Store plugins: `auditTrails`, `files`, `lifecycle`, `relations`, `search`, `selection` +- Column/field/filter generation from schema — `columnsFromSchema()`, `fieldsFromSchema()` +- NO custom Pinia stores for CRUD, Vuex, or manual API call management + +**Chat & AI** (use ChatService): +- Multi-turn conversation — `ChatService` +- RAG-based knowledge retrieval — `ContextRetrievalHandler` +- LLM response generation — `ResponseGenerationHandler` + +**Data Retention & Archival** (use ArchivalService): +- Legal hold — `LegalHoldService` +- Destruction schedules — `DestructionService` +- Retention policies — `RetentionService` + +**Semantic & Hybrid Search** (use SolrController + SettingsController): +- Semantic search via vector embeddings — `SettingsController.semanticSearch()` +- Hybrid search (keyword + semantic combined) — `SolrController.hybridSearch()` +- Vector embedding generation — `VectorizationService` +- NO custom search algorithms — configure via OpenRegister settings + +**GraphQL API** (use GraphQLController): +- Query objects across schemas via GraphQL — `GraphQLController.execute()` +- Alternative to REST for complex cross-entity queries + +**Organization / Multi-Tenancy** (use OrganisationController): +- Organization CRUD — `OrganisationController` +- Tenant-scoped data isolation — automatic via `TenantLifecycleService` +- NO custom multi-tenancy logic + +**Task & Workflow Management** (use TasksController + WorkflowEngineController): +- Task creation and tracking — `TasksController` +- Workflow orchestration — `WorkflowEngineRegistry` +- Scheduled workflows — `ScheduledWorkflowController` +- NO custom task/workflow systems + +**Text Extraction** (use FileTextController): +- Extract text from PDFs and Office docs — `TextExtractionService` +- Entity recognition (PII detection) — `EntityRecognitionHandler` +- Content anonymization — automatic + +**Timeline & Stages** (use CnTimelineStages): +- Workflow progression visualization — `CnTimelineStages` component +- Stage tracking with status colors + +### What apps SHOULD build (custom business logic only): +- External API integrations (SAP, Peppol, TenderNed, etc.) +- PDF/document generation with business-specific templates +- Workflow triggers and business rules specific to the domain +- Notification dispatch with app-specific event types +- Custom settings pages with app-specific configuration +- Background jobs for domain-specific processing diff --git a/.claude/openspec/architecture/adr-002-api.md b/.claude/openspec/architecture/adr-002-api.md new file mode 100644 index 00000000..4f956593 --- /dev/null +++ b/.claude/openspec/architecture/adr-002-api.md @@ -0,0 +1,6 @@ +- URL pattern: `/index.php/apps/{app}/api/{resource}` — lowercase plural, hyphens. +- Methods: GET=read, POST=create, PUT=update, DELETE=remove. No custom methods. +- Pagination: support `_page` + `_limit`. Response includes `total`, `page`, `pages`. +- Errors: appropriate HTTP status + `message` field. NO stack traces in responses. +- Auth: Nextcloud built-in only. NO custom login/session/token flows. +- Public endpoints: annotate `#[PublicPage]` + `#[NoCSRFRequired]`. Register CORS OPTIONS route. diff --git a/.claude/openspec/architecture/adr-003-backend.md b/.claude/openspec/architecture/adr-003-backend.md new file mode 100644 index 00000000..82abe764 --- /dev/null +++ b/.claude/openspec/architecture/adr-003-backend.md @@ -0,0 +1,14 @@ +- **Controller → Service → Mapper** (strict 3-layer). Controllers NEVER call mappers directly. +- Controllers: thin (<10 lines/method). Routing + validation + response only. +- Services: ALL business logic. Stateless — no instance state between requests. +- Mappers: DB CRUD only. No business logic. +- DI: constructor injection with `private readonly`. NO `\OC::$server` or static locators. +- Entity setters: POSITIONAL args only. `$e->setName('val')` — NEVER `$e->setName(name: 'val')`. + (`__call` passes `['name' => val]` but `setter()` uses `$args[0]`.) +- Routes: `appinfo/routes.php`. Specific routes BEFORE wildcard `{slug}` routes. +- Config: `IAppConfig` with sensitive flag for secrets. NEVER read DB directly. +- Lifecycle: schema init via repair steps (`IRepairStep`), background via job queue, events via dispatcher. +- **Spec traceability**: every class and public method MUST have `@spec` PHPDoc tag(s) linking to + the OpenSpec change that caused it: `@spec openspec/changes/{name}/tasks.md#task-N`. + Multiple `@spec` tags allowed (code touched by multiple changes). File-level `@spec` in header docblock. + This enables: code → docblock → spec traceability alongside code → git blame → commit → issue → spec. diff --git a/.claude/openspec/architecture/adr-004-frontend.md b/.claude/openspec/architecture/adr-004-frontend.md new file mode 100644 index 00000000..07737117 --- /dev/null +++ b/.claude/openspec/architecture/adr-004-frontend.md @@ -0,0 +1,255 @@ +- **Vue 2 + Pinia + @nextcloud/vue + @conduction/nextcloud-vue**. NO Vuex. Options API only. +- State: Pinia stores in `src/store/modules/`. Use `createObjectStore` for OpenRegister CRUD. +- API calls: `axios` from `@nextcloud/axios` — auto-attaches CSRF token. NEVER raw `fetch()` for mutations. + Loading state with `try/finally`. +- Translations: ALL user-visible strings via `t(appName, 'text')`. NO hardcoded strings. + Translation keys MUST be English — Dutch translations go in `l10n/nl.json`. +- CSS: ONLY Nextcloud CSS variables (`var(--color-primary-element)`, etc.). NO hardcoded colors. + NEVER reference `--nldesign-*` directly — nldesign app handles theming. +- Router: history mode, base `generateUrl('/apps/{app}/')`. Requires matching PHP routes in `routes.php`. + Deep link URL templates MUST match the router mode — use path format (`/apps/{app}/entities/{uuid}`), + NOT hash format (`/apps/{app}/#/entities/{uuid}`). +- OpenRegister dependency: settings returns `openRegisters` (bool) + `isAdmin`. + Show empty state if OR missing. NEVER use `OC.isAdmin` — get from backend. +- NEVER `window.confirm()` or `window.alert()` — use `NcDialog` or `CnFormDialog` (WCAG, theming). +- NEVER read app state from DOM (`document.getElementById`, `dataset`) — use backend API or store. +- NEVER pass server-side data (e.g. app version) via DOM attributes. Use `IInitialState::provideInitialState('key', $value)` in PHP and `loadState('appid', 'key', default)` from `@nextcloud/initial-state` in Vue. DOM data-attributes are not the Nextcloud-idiomatic pattern and break on CSP-hardened instances. +- NEVER add admin settings Vue components (e.g. `AdminRoot.vue`) to the vue-router. Admin settings are registered via `AdminSettings.php` and rendered by Nextcloud's settings framework — adding them to the router makes them publicly accessible as frontend routes, bypassing all server-side access checks. +- NEVER create manual `