From f45f24c58bc4a86aec5376a442aea517e92756b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 30 Aug 2026 22:12:37 +0200 Subject: [PATCH 01/21] build(deps-dev): bump node-polyfill-webpack-plugin from 4.0.0 to 4.1.0 (#1014) Bumps [node-polyfill-webpack-plugin](https://github.com/Richienb/node-polyfill-webpack-plugin) from 4.0.0 to 4.1.0. - [Release notes](https://github.com/Richienb/node-polyfill-webpack-plugin/releases) - [Commits](https://github.com/Richienb/node-polyfill-webpack-plugin/compare/v4.0.0...v4.1.0) --- updated-dependencies: - dependency-name: node-polyfill-webpack-plugin dependency-version: 4.1.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 182 +++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 91 insertions(+), 93 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4e0782e26..8db574e46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,7 +49,7 @@ "css-loader": "~7.1.1", "eslint": "^10.9.0", "eslint-config-prettier": "^10.1.8", - "node-polyfill-webpack-plugin": "4.0.0", + "node-polyfill-webpack-plugin": "4.1.0", "postcss-html": "^1.0.0", "prettier": "^3.9.6", "style-loader": "~4.0.0", @@ -4597,19 +4597,6 @@ "node": "^18.17.0 || >=20.5.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==", - "dev": true, - "license": "MIT", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, "node_modules/acorn": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", @@ -5063,6 +5050,16 @@ "dev": true, "license": "MIT" }, + "node_modules/browser-resolve": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", + "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "^1.17.0" + } + }, "node_modules/browserify-aes": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", @@ -5250,7 +5247,6 @@ } ], "license": "MIT", - "optional": true, "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -5824,6 +5820,13 @@ "sha.js": "^2.4.8" } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/crelt": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.7.tgz", @@ -6337,13 +6340,13 @@ } }, "node_modules/domain-browser": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-5.7.0.tgz", - "integrity": "sha512-edTFu0M/7wO1pXY6GDxVNVW086uqwWYIHP98txhcPyV995X21JIH2DtYp33sQJOupYoXKe9RwTw2Ya2vWaquTQ==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.22.0.tgz", + "integrity": "sha512-IGBwjF7tNk3cwypFNH/7bfzBcgSCbaMOD3GsaY1AU/JRrnHnYgEM0+9kQt52iZxjNsjBtJYtao146V+f8jFZNw==", "dev": true, - "license": "Artistic-2.0", + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=10" }, "funding": { "url": "https://bevry.me/fund" @@ -7286,16 +7289,6 @@ "node": ">=0.10.0" } }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/eventemitter3": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", @@ -8863,6 +8856,16 @@ "node": ">=0.10.0" } }, + "node_modules/isomorphic-timers-promises": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-timers-promises/-/isomorphic-timers-promises-1.0.1.tgz", + "integrity": "sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", @@ -10872,36 +10875,14 @@ } }, "node_modules/node-polyfill-webpack-plugin": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/node-polyfill-webpack-plugin/-/node-polyfill-webpack-plugin-4.0.0.tgz", - "integrity": "sha512-WLk77vLpbcpmTekRj6s6vYxk30XoyaY5MDZ4+9g8OaKoG3Ij+TjOqhpQjVUlfDZBPBgpNATDltaQkzuXSnnkwg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/node-polyfill-webpack-plugin/-/node-polyfill-webpack-plugin-4.1.0.tgz", + "integrity": "sha512-b4ei444EKkOagG/yFqojrD3QTYM5IOU1f8tn9o6uwrG4qL+brI7oVhjPVd0ZL2xy+Z6CP5bu9w8XTvlWgiXHcw==", "dev": true, "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": "^5.7.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.1", - "querystring-es3": "^0.2.1", - "readable-stream": "^4.5.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.18.2", - "url": "^0.11.3", - "util": "^0.12.5", - "vm-browserify": "^1.1.2" + "node-stdlib-browser": "^1.3.0", + "type-fest": "^4.27.0" }, "engines": { "node": ">=14" @@ -10910,58 +10891,75 @@ "webpack": ">=5" } }, - "node_modules/node-polyfill-webpack-plugin/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "node_modules/node-releases": { + "version": "2.0.51", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", + "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", "dev": true, - "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" + "engines": { + "node": ">=18" } }, - "node_modules/node-polyfill-webpack-plugin/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==", + "node_modules/node-stdlib-browser": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-stdlib-browser/-/node-stdlib-browser-1.3.1.tgz", + "integrity": "sha512-X75ZN8DCLftGM5iKwoYLA3rjnrAEs97MkzvSd4q2746Tgpg8b8XWiBGiBG4ZpgcAqBgtgPHTiAc8ZMCvZuikDw==", "dev": true, "license": "MIT", "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", + "assert": "^2.0.0", + "browser-resolve": "^2.0.0", + "browserify-zlib": "^0.2.0", + "buffer": "^5.7.1", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "create-require": "^1.1.1", + "crypto-browserify": "^3.12.1", + "domain-browser": "4.22.0", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "isomorphic-timers-promises": "^1.0.1", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.1", + "pkg-dir": "^5.0.0", "process": "^0.11.10", - "string_decoder": "^1.3.0" + "punycode": "^1.4.1", + "querystring-es3": "^0.2.1", + "readable-stream": "^3.6.0", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.1", + "url": "^0.11.4", + "util": "^0.12.4", + "vm-browserify": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=10" } }, - "node_modules/node-releases": { - "version": "2.0.51", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", - "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", + "node_modules/node-stdlib-browser/node_modules/pkg-dir": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", "dev": true, "license": "MIT", + "dependencies": { + "find-up": "^5.0.0" + }, "engines": { - "node": ">=18" + "node": ">=10" } }, + "node_modules/node-stdlib-browser/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==", + "dev": true, + "license": "MIT" + }, "node_modules/nopt": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", diff --git a/package.json b/package.json index d1d816ff8..2460644cd 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "css-loader": "~7.1.1", "eslint": "^10.9.0", "eslint-config-prettier": "^10.1.8", - "node-polyfill-webpack-plugin": "4.0.0", + "node-polyfill-webpack-plugin": "4.1.0", "postcss-html": "^1.0.0", "prettier": "^3.9.6", "style-loader": "~4.0.0", From c961918e528576304c4fc4696dd36d7bb1da4073 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 30 Aug 2026 22:12:45 +0200 Subject: [PATCH 02/21] build(deps-dev): bump @vue/compiler-sfc from 3.5.41 to 3.5.42 (#1013) Bumps [@vue/compiler-sfc](https://github.com/vuejs/core/tree/HEAD/packages/compiler-sfc) from 3.5.41 to 3.5.42. - [Release notes](https://github.com/vuejs/core/releases) - [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md) - [Commits](https://github.com/vuejs/core/commits/v3.5.42/packages/compiler-sfc) --- updated-dependencies: - dependency-name: "@vue/compiler-sfc" dependency-version: 3.5.42 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 50 +++++++++++++++++++++++------------------------ package.json | 2 +- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8db574e46..267e80aae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,7 +45,7 @@ "@playwright/test": "^1.59.1", "@typescript-eslint/parser": "^8.67.0", "@vitest/coverage-v8": "4.1.11", - "@vue/compiler-sfc": "^3.5.41", + "@vue/compiler-sfc": "^3.5.42", "css-loader": "~7.1.1", "eslint": "^10.9.0", "eslint-config-prettier": "^10.1.8", @@ -4146,16 +4146,16 @@ } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.41", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.41.tgz", - "integrity": "sha512-XJhip7R2wy6vX3knCxdZN4KracFaZUef58s1KYewqluedHIJaPIVfXoYT7MF1F8nCvv6k8bWWxDC8opMkg1VTQ==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.42.tgz", + "integrity": "sha512-fkCAFB4okcAANGMThboWnScp/gzWjU0ZSkVnjTIiplmMDq2uq0tIB3j+xVu4rhv5rvOgBySCysudmbMd6xRRqw==", "license": "MIT", "dependencies": { "@babel/parser": "^7.29.8", - "@vue/compiler-core": "3.5.41", - "@vue/compiler-dom": "3.5.41", - "@vue/compiler-ssr": "3.5.41", - "@vue/shared": "3.5.41", + "@vue/compiler-core": "3.5.42", + "@vue/compiler-dom": "3.5.42", + "@vue/compiler-ssr": "3.5.42", + "@vue/shared": "3.5.42", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.19", @@ -4163,42 +4163,42 @@ } }, "node_modules/@vue/compiler-sfc/node_modules/@vue/compiler-core": { - "version": "3.5.41", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.41.tgz", - "integrity": "sha512-q0Xtv/F9w2YO/7htQhtiL+Ev2WCJbe5N2hc+XfgyKkEKqWpSxknmT8QOuGdEKNdjPq0c3F7rNpFkTo3Kfrm7pg==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.42.tgz", + "integrity": "sha512-2Ye1ilMtKXxl8qZUrQ5j0CdgenFp/HFQmta6rfRyfEsTG69L6Wk+tWuNoHYHMx9E8tF2Slvdg1FuwDvAXdy1LQ==", "license": "MIT", "dependencies": { "@babel/parser": "^7.29.8", - "@vue/shared": "3.5.41", + "@vue/shared": "3.5.42", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-sfc/node_modules/@vue/compiler-dom": { - "version": "3.5.41", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.41.tgz", - "integrity": "sha512-oKacVfNglLvGjnS6BXOlGL7EyG2h8X03pqXCjzotRZUaXGjbrTJUnVAQjrCqUnS+lyu31nwQjZY/d817GmCnfw==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.42.tgz", + "integrity": "sha512-qbhQZEFmycr+ni/qyuccS4sucNN7VAbDfbkvNxWOX2VfgFm90MNs3/UhRNKoPMEIVn0F8gdlYjLPvqxHwHeQOA==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.41", - "@vue/shared": "3.5.41" + "@vue/compiler-core": "3.5.42", + "@vue/shared": "3.5.42" } }, "node_modules/@vue/compiler-sfc/node_modules/@vue/compiler-ssr": { - "version": "3.5.41", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.41.tgz", - "integrity": "sha512-U3v5OejKEGqOI0Wy0+Sz7hGuIFZHA4LSXzrNM3IMIeDyJEBBfTpX26n3SDgToRpP2bLc9FfI2j/kSgcJ8Emq5A==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.42.tgz", + "integrity": "sha512-xmLk3wLkbizPAiLyomjgFFosf2ys9b5Ghb+oh/k2tnvipNz8OFrQOiTcWCzyK7MpBp9KkyGtfvgfLUivbmuGYA==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.41", - "@vue/shared": "3.5.41" + "@vue/compiler-dom": "3.5.42", + "@vue/shared": "3.5.42" } }, "node_modules/@vue/compiler-sfc/node_modules/@vue/shared": { - "version": "3.5.41", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.41.tgz", - "integrity": "sha512-IOnwSCma8j+9xJT6b8H0dEYidC80NsYmNMlZxRsukYcSoGaDBohog5hDxzeUXdFeGWFA++vWvxqOmrr96VlqMA==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.42.tgz", + "integrity": "sha512-2rPxex1jQf4jvl9MOHl6YaXCPcrNqz/FstMOEh3QWY+/OME9nQTvl9WYeCwhW7AFjaR0SnngZGlp/wkR6rkI6g==", "license": "MIT" }, "node_modules/@vue/compiler-ssr": { diff --git a/package.json b/package.json index 2460644cd..cce1b42f6 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "@playwright/test": "^1.59.1", "@typescript-eslint/parser": "^8.67.0", "@vitest/coverage-v8": "4.1.11", - "@vue/compiler-sfc": "^3.5.41", + "@vue/compiler-sfc": "^3.5.42", "css-loader": "~7.1.1", "eslint": "^10.9.0", "eslint-config-prettier": "^10.1.8", From d3b0dc1e2853de4abff6e6e6f753bea2bef2ef68 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 30 Aug 2026 22:13:15 +0200 Subject: [PATCH 03/21] build(deps): bump dompurify from 3.4.13 to 3.4.14 (#1006) Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.4.13 to 3.4.14. - [Release notes](https://github.com/cure53/DOMPurify/releases) - [Commits](https://github.com/cure53/DOMPurify/compare/3.4.13...3.4.14) --- updated-dependencies: - dependency-name: dompurify dependency-version: 3.4.14 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 267e80aae..6f2a3e5ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "@vueuse/core": "^14.4.0", "axe-core": "^4.13.0", "dexie": "^4.4.5", - "dompurify": "^3.4.12", + "dompurify": "^3.4.14", "gridstack": "^12.6.0", "marked": "^18.0.9", "pinia": "^3.0.3", @@ -6382,9 +6382,9 @@ } }, "node_modules/dompurify": { - "version": "3.4.13", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.13.tgz", - "integrity": "sha512-2vmYIoqjze2d+kakP8S/nS5shfsl587kzwEjcGlTdiksUVgFHnFCsLYDVj/JNqJVOQZGSYBTmuycv0PodwmnMQ==", + "version": "3.4.14", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.14.tgz", + "integrity": "sha512-dVoH9z+MY+C9IilgGCk3YfFqjLi3fChm2OiKJMzh6axrJ5qwxqWaZamgmHrpv22CN/KdbZJuGEGgfQoL00LTdg==", "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" diff --git a/package.json b/package.json index cce1b42f6..89b61dc55 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "@vueuse/core": "^14.4.0", "axe-core": "^4.13.0", "dexie": "^4.4.5", - "dompurify": "^3.4.12", + "dompurify": "^3.4.14", "gridstack": "^12.6.0", "marked": "^18.0.9", "pinia": "^3.0.3", From 3cedc9cd00ad7a1c8d114fe644f8a3f405cd23e9 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Sun, 30 Aug 2026 22:32:40 +0200 Subject: [PATCH 04/21] chore(dependabot): hold back vue-router 5 as well (#1027) * feat(setup): ask which example set to load, instead of planting one on install Installing this app planted 334 objects nobody asked for. SettingsService::loadConfiguration() merges decidesk_register.json with all 26 register.d fragments, and every one of them carried its own x-openregister.seedData.objects. The InitializeSettings repair step runs that merge, so a fresh install seeded a Gemeenteraad Amsterdam, a VvE Zeewaarts, a pub quiz, five ACME B.V. bodies and eight placeholder TOOI mappings into the operator's register. A municipality got the VvE data. A VvE got the council data. Nobody chose any of it. The wizard meanwhile offered a DIFFERENT dataset, whose own step text said "Skip this on a production install". By the time an operator read that sentence, 334 objects were already in their register. So the fragments now declare schemas only, and the objects live in lib/Settings/profiles/, one file per example set. A bare install plants nothing; the wizard asks which organisation this is for, and loads that. ## The split had to be a closure, not a partition The seeds cross-reference each other by slug. The reference graph has one connected component of 170 objects tangling municipal, corporate and association bodies together, so no partition exists. Each set is instead anchored on its governance bodies and closed over outbound references, so every reference resolves inside the set carrying it. Sets may overlap, and 15 objects do. Verified: 334 of 334 classified, zero dangling references, zero orphans. ## Why the descriptor declares no register An example set carries @self.configuration/register/schema on every object and declares NO components.registers. That is load-bearing. ImportHandler::importRegister() calls setApplication($appId) unconditionally when it updates an existing register, so a descriptor that declared decidiq would re-point the register at the profile's config id and hydrate over its authorization block: the baseline that stops any authenticated user rewriting another body's decisions. Verified on a live instance: importing this shape left application=decidiq, the version and the authorization hash byte-identical, imported 45 objects, and added nothing on a second run. The files sit in a SUBDIRECTORY because RegisterDescriptorService scans lib/Settings/*.json non-recursively and indexes by declared register slug; four profiles in lib/Settings would collide with each other and with the app's own register. ## Two wizard steps, because an action carries no body CnSetupWizard::runAction() posts to /api/setup/action/{action} with no body, so an action cannot carry the answer. A choice step records which set via the new POST /api/setup/config, and the run-action step reads it back. ADR-111 keeps the schema-generated mock on offer, so it is one option in the same choice rather than a second question about the same thing. ## Ten pre-existing defects this surfaced, all fixed Validating every seed against its schema found: - Three seeds keyed on `regulation`, which is not a decidiq schema slug: the app's is `regeling`. Because importSeedData() resolves a slug cross-app with multitenancy off, `regulation` resolves to LEARNIQ's schema. - Regeling.status was required and named by x-openregister-lifecycle, but never declared as a property, so OpenRegister created no magic-table column. Measured: oc_openregister_table_21_262 carried every other property and no status column, which means the declared in-preparation -> adopted -> in-effect -> lapsed map could never advance a regulation. - Six invalid enum values on the pub-quiz decision-stage seeds. - Two governance bodies missing the required `domain`. - The works-council seeds described a city council: all three WOR consultation requests carried governanceBody: gemeenteraad-amsterdam, a null-UUID director, and a raadsvergadering as their overlegvergadering. Replaced with a real 45-object set built around an ondernemingsraad at ACME B.V. ## Verification 1235 PHP unit tests and 378 vitest tests pass. PHPCS 0 errors, PHPMD, PHPStan and Psalm clean. Manifest validates against schema 2.26.0. The manifest-drift guard was proved to FAIL when the manifest and the shipped sets disagree. Two hydra gates (22, 53) still fail, and did before this change: hydra-gates v1.10.0 vendors manifest schema 2.25.0, which predates the `flow` page type that FlowDetail already used. That is fleet debt in ConductionNL/.github. * chore(dependabot): hold back vue-router 5 as well vue-router 5 peers `vite: ^7.3.0 || ^8.0.0` and expects a Vite toolchain. These apps build with webpack, which cannot resolve it at all: the build dies on `Can't resolve 'vue-router'` from src and from @nextcloud/vue's own chunks. Adopting it is a Vite migration, not a version bump. Dependabot proposed it across 8 repositories in a single run, and merging any one of them takes that app's build from green to red with no code change that can fix it. versioniq already builds with Vite and is the natural pilot if the fleet does move. Lift this when an app's toolchain can actually take it. --------- Co-authored-by: Ruben van der Linde --- .github/dependabot.yml | 7 + appinfo/routes.php | 4 + l10n/nl.json | 6 +- lib/Controller/SetupController.php | 149 +- lib/Service/SeedProfileService.php | 366 ++ lib/Settings/decidesk_register.json | 1438 +----- lib/Settings/profiles/association.json | 1453 ++++++ lib/Settings/profiles/corporate.json | 2151 +++++++++ lib/Settings/profiles/municipality.json | 4111 +++++++++++++++++ lib/Settings/profiles/works-council.json | 755 +++ .../register.d/43-process-config-v1.json | 383 +- .../45-toezeggingen-ingekomen-stukken.json | 105 +- .../register.d/46-urgency-policy.json | 189 +- .../47-works-council-consultation.json | 124 +- .../48-constituency-consultation.json | 92 +- .../49-vragenuur-interpellatie.json | 170 +- lib/Settings/register.d/50-termijnagenda.json | 81 +- .../register.d/51-raadsinformatiebrieven.json | 83 +- lib/Settings/register.d/52-pc-cyclus.json | 313 +- .../register.d/53-verordeningenregister.json | 112 +- .../54-delegatie-mandaatregister.json | 97 +- .../55-governing-documents-register.json | 111 +- .../56-shared-governance-bodies.json | 161 +- lib/Settings/register.d/57-vve-alv-pack.json | 188 +- .../register.d/58-woo-diwoo-publication.json | 82 +- .../register.d/59-member-onboarding.json | 286 +- .../60-advisory-opinion-workflow.json | 78 +- .../register.d/61-appointments-and-terms.json | 89 +- .../62-interests-and-integrity.json | 137 +- .../63-member-proxy-authorization.json | 79 +- .../register.d/65-embargo-geheimhouding.json | 133 +- .../register.d/66-organisation-goals.json | 73 +- .../register.d/67-model-debt-cleanup.json | 53 +- .../68-unified-decision-templates.json | 370 +- .../register.d/69-approval-routes.json | 93 +- .../register.d/70-configurable-types.json | 383 +- openspec/changes/seed-profiles/proposal.md | 69 + .../seed-profiles/specs/seed-profiles/spec.md | 139 + openspec/changes/seed-profiles/tasks.md | 31 + src/manifest.json | 42 +- tests/Unit/Controller/SetupControllerTest.php | 113 +- tests/Unit/RegisterJsonTest.php | 84 +- tests/Unit/Service/SeedProfileServiceTest.php | 150 + .../demo-data-setup-step.spec.ts | 161 - .../example-set-setup-step.spec.ts | 231 + 45 files changed, 9935 insertions(+), 5590 deletions(-) create mode 100644 lib/Service/SeedProfileService.php create mode 100644 lib/Settings/profiles/association.json create mode 100644 lib/Settings/profiles/corporate.json create mode 100644 lib/Settings/profiles/municipality.json create mode 100644 lib/Settings/profiles/works-council.json create mode 100644 openspec/changes/seed-profiles/proposal.md create mode 100644 openspec/changes/seed-profiles/specs/seed-profiles/spec.md create mode 100644 openspec/changes/seed-profiles/tasks.md create mode 100644 tests/Unit/Service/SeedProfileServiceTest.php delete mode 100644 tests/e2e/spec-coverage/demo-data-setup-step.spec.ts create mode 100644 tests/e2e/spec-coverage/example-set-setup-step.spec.ts diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 7a8476c50..786b63176 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -26,6 +26,13 @@ updates: ignore: - dependency-name: "typescript" update-types: ["version-update:semver-major"] + # vue-router 5 peers `vite: ^7.3.0 || ^8.0.0` and expects a Vite + # toolchain. These apps build with webpack, which cannot resolve it at + # all: the build dies on `Can't resolve 'vue-router'`. Adopting it is a + # Vite migration, not a bump. versioniq is already on Vite and is the + # natural pilot. + - dependency-name: "vue-router" + update-types: ["version-update:semver-major"] - dependency-name: "webpack-cli" update-types: ["version-update:semver-major"] - dependency-name: "@babel/core" diff --git a/appinfo/routes.php b/appinfo/routes.php index 4bf7c702f..7111328ba 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -37,6 +37,10 @@ // First-time setup wizard (ADR-042) - the standard CnSetupWizard contract. ['name' => 'setup#status', 'url' => '/api/setup/status', 'verb' => 'GET'], ['name' => 'setup#runAction', 'url' => '/api/setup/action/{actionId}', 'verb' => 'POST', 'requirements' => ['actionId' => '[a-z0-9\\-]+']], + // A `choice` step POSTs its answer here before it advances; the + // `run-action` step that follows reads it back, because runAction() + // carries no body and so cannot carry the answer itself. + ['name' => 'setup#saveConfig', 'url' => '/api/setup/config', 'verb' => 'POST'], ['name' => 'settings#getPublicationConfig', 'url' => '/api/settings/publication-config', 'verb' => 'GET'], ['name' => 'settings#setPublicationConfig', 'url' => '/api/settings/publication-config', 'verb' => 'PUT'], diff --git a/l10n/nl.json b/l10n/nl.json index 4c25fe819..235bc38bf 100644 --- a/l10n/nl.json +++ b/l10n/nl.json @@ -2036,7 +2036,11 @@ "{n} meeting(s) exceeded the scheduled time": "{n} vergadering(en) overschreden de geplande tijd", "{n} open action items": "{n} openstaande actiepunten", "{responded} of {invited} responded": "{responded} van {invited} gereageerd", - "{states} states, {transitions} transitions": "{states} statussen, {transitions} overgangen" + "{states} states, {transitions} transitions": "{states} statussen, {transitions} overgangen", + "Which kind of organisation is this for?": "Voor wat voor organisatie is dit?", + "Pick the organisation this app runs for and you get a worked example of it: bodies, meetings, decisions and templates that fit. Installing the app plants nothing on its own, so this is the only step that adds data. Choose \"None\" on a production install.": "Kies de organisatie waarvoor deze app draait en je krijgt een uitgewerkt voorbeeld: organen, vergaderingen, besluiten en sjablonen die daarbij passen. De app zet zelf niets klaar, dus dit is de enige stap die gegevens toevoegt. Kies \"Geen\" op een productieomgeving.", + "Load the example data": "Laad de voorbeeldgegevens", + "Loads the set you picked. The data is obviously sample data, it is safe to run more than once, and you can delete it afterwards.": "Laadt de set die je koos. De gegevens zijn herkenbaar voorbeeldgegevens, je kunt dit meer dan een keer uitvoeren en je kunt ze daarna verwijderen." }, "plurals": null, "pluralForm": "nplurals=2; plural=(n != 1);" diff --git a/lib/Controller/SetupController.php b/lib/Controller/SetupController.php index 03e153972..b9afd3c19 100644 --- a/lib/Controller/SetupController.php +++ b/lib/Controller/SetupController.php @@ -7,11 +7,12 @@ * GET /api/setup/status per-step state * POST /api/setup/action/{actionId} run a privileged server-side action * - * This app declares no configuration of its own yet, so the wizard orients and - * offers the demo data the app ALREADY ships — a dataset generated from its own - * schemas that no operator could previously reach. It deliberately does not - * invent configuration steps: a wizard that asks questions the app does not act - * on is worse than none. + * The wizard orients, then asks the ONE question a new administrator actually + * has: which kind of organisation is this for? The answer picks an example set, + * and the app plants that set and nothing else. + * + * It deliberately does not invent further configuration steps: a wizard that + * asks questions the app does not act on is worse than none. * * @category Controller * @package OCA\Decidiq\Controller @@ -36,7 +37,7 @@ use OCP\IAppConfig; use OCP\IRequest; use Psr\Log\LoggerInterface; -use OCA\Decidiq\Service\DemoDataService; +use OCA\Decidiq\Service\SeedProfileService; /** * First-time setup wizard endpoints. @@ -65,13 +66,26 @@ class SetupController extends Controller { */ private const DEMO_DECIDED_KEY = 'demo_data_decided'; + /** + * App-config key holding the example set the operator picked. + * + * The wizard's `choice` step writes it through `POST /api/setup/config`, and + * the `run-action` step that follows reads it back. Two steps rather than + * one because `CnSetupWizard::runAction()` posts to + * `/api/setup/action/{action}` with no body: an action cannot carry the + * answer, so the answer has to be stored before the action runs. + * + * @var string + */ + private const PROFILE_KEY = 'example_profile'; + /** * Constructor. * - * @param IRequest $request The request. - * @param IAppConfig $appConfig Records the demo-data decision. - * @param LoggerInterface $logger Records a failed import. - * @param DemoDataService $demoDataService Imports the shipped demo dataset. + * @param IRequest $request The request. + * @param IAppConfig $appConfig Records the operator's answer. + * @param LoggerInterface $logger Records a failed import. + * @param SeedProfileService $seedProfiles Lists and imports the example sets. * * @return void */ @@ -79,7 +93,7 @@ public function __construct( IRequest $request, private readonly IAppConfig $appConfig, private readonly LoggerInterface $logger, - private readonly DemoDataService $demoDataService, + private readonly SeedProfileService $seedProfiles, ) { parent::__construct(appName: Application::APP_ID, request: $request); @@ -89,8 +103,8 @@ public function __construct( * Report per-step setup status for the wizard. * * `completed` is deliberately TRUE: this app declares no REQUIRED step, so - * setup must never gate the app. The demo-data step is reported so the wizard - * can stop asking once it has an answer. + * setup must never gate the app. Both example-set steps are reported so the + * wizard can stop asking once it has an answer. * * @return JSONResponse The status document. * @@ -98,26 +112,87 @@ public function __construct( */ #[AuthorizedAdminSetting(AdminSettings::class)] public function status(): JSONResponse { + $picked = $this->appConfig->getValueString(Application::APP_ID, self::PROFILE_KEY, ''); $demoDecided = $this->appConfig->getValueString(Application::APP_ID, self::DEMO_DECIDED_KEY, '') !== ''; return new JSONResponse( data: [ 'version' => self::SETUP_VERSION, 'completed' => true, + 'profiles' => $this->seedProfiles->listProfiles(), 'steps' => [ - 'demo-data' => ['done' => $demoDecided], + 'example-set' => ['done' => ($picked !== '')], + // "None" is an ANSWER, so the load step is finished the moment + // it is chosen: there is nothing left for the operator to run. + 'load-example-set' => [ + 'done' => ($demoDecided === true || $picked === SeedProfileService::NONE_PROFILE), + ], ], ] ); }//end status() + /** + * Persist the wizard's `choice` and `config-fields` answers. + * + * The `CnSetupWizard` contract: a `choice` step POSTs + * `{ : }` here before it advances. + * + * @return JSONResponse `{ success, config }`. + * + * @spec openspec/changes/seed-profiles/specs/seed-profiles/spec.md#requirement-record-the-chosen-example-set + */ + #[AuthorizedAdminSetting(AdminSettings::class)] + public function saveConfig(): JSONResponse { + // 🔴 ONE NAMED KEY, NEVER A CALLER-SUPPLIED ONE. The body arrives from the + // browser, and this app's own settings share the appconfig namespace — + // including `voter_token_secret`, the HMAC key signing every voting token + // and mail-reply link. Looping over the posted keys would let this + // endpoint rotate that secret and silently invalidate every outstanding + // vote link, so the key is written in the source and only its value comes + // from the request. + $value = $this->request->getParam(self::PROFILE_KEY); + if ($value === null) { + return new JSONResponse(data: ['success' => true, 'config' => []]); + } + + $profileId = (string)$value; + if ($this->isSelectableProfile(profileId: $profileId) === false) { + return new JSONResponse( + data: ['success' => false, 'message' => 'No example set is called "' . $profileId . '".'], + statusCode: Http::STATUS_BAD_REQUEST, + ); + } + + $this->appConfig->setValueString(Application::APP_ID, self::PROFILE_KEY, $profileId); + + return new JSONResponse(data: ['success' => true, 'config' => [self::PROFILE_KEY => $profileId]]); + + }//end saveConfig() + + /** + * Whether a value is one the choice step may legitimately carry. + * + * @param string $profileId The submitted value. + * + * @return boolean True when it names a set, or declines one. + */ + private function isSelectableProfile(string $profileId): bool { + if ($profileId === SeedProfileService::NONE_PROFILE) { + return true; + } + + return $this->seedProfiles->isKnown(profileId: $profileId); + + }//end isSelectableProfile() + /** * Run a privileged server-side setup action. * * Admin-only by Nextcloud's default for an un-attributed method. * - * @param string $actionId One of `install-demo-data` | `skip-demo-data`. + * @param string $actionId One of `load-example-set` | `skip-example-set`. * * @return JSONResponse `{ success, message }`. * @@ -125,15 +200,15 @@ public function status(): JSONResponse { */ #[AuthorizedAdminSetting(AdminSettings::class)] public function runAction(string $actionId): JSONResponse { - if ($actionId === 'install-demo-data') { - return $this->installDemoData(); + if ($actionId === 'load-example-set') { + return $this->loadExampleSet(); } // DECLINING IS AN ANSWER — see DEMO_DECIDED_KEY. - if ($actionId === 'skip-demo-data') { + if ($actionId === 'skip-example-set') { $this->appConfig->setValueString(Application::APP_ID, self::DEMO_DECIDED_KEY, 'skipped'); - return new JSONResponse(data: ['success' => true, 'message' => 'Demo data skipped.']); + return new JSONResponse(data: ['success' => true, 'message' => 'No example data was loaded.']); } return new JSONResponse( @@ -144,25 +219,43 @@ public function runAction(string $actionId): JSONResponse { }//end runAction() /** - * Import the shipped demo dataset. + * Import the example set the operator picked in the previous step. * * Reports the FAILURE rather than a quiet success: an operator who asked for - * demo data and got none must be told, which is why DemoDataService::install() - * throws instead of returning an empty result. + * example data and got none must be told, which is why + * SeedProfileService::install() throws instead of returning an empty result. * * @return JSONResponse `{ success, message }`. */ - private function installDemoData(): JSONResponse { + private function loadExampleSet(): JSONResponse { + $profileId = $this->appConfig->getValueString(Application::APP_ID, self::PROFILE_KEY, ''); + + // 🔴 NO SILENT DEFAULT. Guessing a set here would plant a municipality + // into an operator's register because they clicked Run one step early, + // which is the exact failure this whole change exists to remove. + if ($profileId === '') { + return new JSONResponse( + data: ['success' => false, 'message' => 'Pick an example set first.'], + statusCode: Http::STATUS_BAD_REQUEST, + ); + } + + if ($profileId === SeedProfileService::NONE_PROFILE) { + $this->appConfig->setValueString(Application::APP_ID, self::DEMO_DECIDED_KEY, 'skipped'); + + return new JSONResponse(data: ['success' => true, 'message' => 'No example data was loaded.']); + } + try { - $imported = $this->demoDataService->install(); + $imported = $this->seedProfiles->install(profileId: $profileId); } catch (\Throwable $e) { $this->logger->error( - 'Setup install-demo-data failed: ' . $e->getMessage(), + 'Setup load-example-set failed for "' . $profileId . '": ' . $e->getMessage(), ['app' => Application::APP_ID, 'exception' => $e] ); return new JSONResponse( - data: ['success' => false, 'message' => 'Could not import the demo data: ' . $e->getMessage()], + data: ['success' => false, 'message' => 'Could not import the example data: ' . $e->getMessage()], statusCode: Http::STATUS_INTERNAL_SERVER_ERROR, ); } @@ -172,9 +265,9 @@ private function installDemoData(): JSONResponse { return new JSONResponse( data: [ 'success' => true, - 'message' => 'Imported ' . $imported['objects'] . ' demo object(s).', + 'message' => 'Imported ' . $imported['objects'] . ' example object(s).', ] ); - }//end installDemoData() + }//end loadExampleSet() }//end class diff --git a/lib/Service/SeedProfileService.php b/lib/Service/SeedProfileService.php new file mode 100644 index 000000000..0afeeb683 --- /dev/null +++ b/lib/Service/SeedProfileService.php @@ -0,0 +1,366 @@ + + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * @link https://conduction.nl + */ + +declare(strict_types=1); + +namespace OCA\Decidiq\Service; + +use OCA\Decidiq\AppInfo\Application; +use OCP\App\IAppManager; +use Psr\Container\ContainerInterface; +use Psr\Log\LoggerInterface; +use RuntimeException; + +/** + * Lists the example sets this app ships and imports the one an operator picked. + * + * @spec openspec/changes/seed-profiles/specs/seed-profiles/spec.md + */ +class SeedProfileService { + /** + * App-relative directory holding the example-set descriptors. + * + * 🔴 A SUBDIRECTORY ON PURPOSE. OpenRegister's `RegisterDescriptorService` + * scans `lib/Settings/*.json` NON-recursively and indexes what it finds by + * the register slug the file declares. Four profile files sitting in + * `lib/Settings` would therefore collide with each other and with + * `decidesk_register.json`, and `descriptorFor()` returns the FIRST match, + * so `occ openregister:descriptors:list` would silently describe one + * arbitrary profile as this app's register. + * + * @var string + */ + private const PROFILE_DIR = '/lib/Settings/profiles'; + + /** + * The one profile id that is not a file: OpenRegister's generated mock. + * + * ADR-111 rule 2 requires the schema-generated dataset to stay on offer, and + * rule 1 requires the walkthrough to open with it. Folding it in here as an + * option keeps the operator's question single ("which example set?") instead + * of asking twice about the same thing in two different steps. + * + * @var string + */ + public const GENERATED_PROFILE = 'generated'; + + /** + * The answer that means "plant nothing". + * + * 🔴 NOT THE ABSENCE OF AN ANSWER. An operator who declines has FINISHED the + * step; a step that can never be marked done reopens the wizard over every + * page (nextcloud-vue#806). + * + * @var string + */ + public const NONE_PROFILE = 'none'; + + /** + * Constructor. + * + * @param IAppManager $appManager Resolves this app's path and version. + * @param ContainerInterface $container Resolves OpenRegister's importer. + * @param LoggerInterface $logger Records what was imported. + * @param DemoDataService $demoData Imports the ADR-111 generated dataset. + * + * @return void + */ + public function __construct( + private readonly IAppManager $appManager, + private readonly ContainerInterface $container, + private readonly LoggerInterface $logger, + private readonly DemoDataService $demoData, + ) { + }//end __construct() + + /** + * Every example set this app ships, in the order the wizard should offer them. + * + * Read from disk rather than from a list in code: the descriptors ARE the + * source of truth, so a set that ships without being listed here is + * impossible by construction. + * + * @return array The sets. + * + * @spec openspec/changes/seed-profiles/specs/seed-profiles/spec.md#requirement-list-example-sets + */ + public function listProfiles(): array { + $profiles = []; + foreach ($this->descriptorFiles() as $file) { + $meta = $this->readProfileMeta(path: $file); + if ($meta !== null) { + $profiles[] = $meta; + } + } + + usort($profiles, static fn (array $a, array $b): int => ($a['order'] <=> $b['order'])); + + $listed = []; + foreach ($profiles as $profile) { + unset($profile['order']); + $listed[] = $profile; + } + + if ($this->demoData->isAvailable() === true) { + $listed[] = [ + 'id' => self::GENERATED_PROFILE, + 'label' => 'Every schema, generated values', + 'description' => 'Sample values generated from the schemas themselves. Use it to exercise the data model, not to demo the app.', + 'objectCount' => 0, + ]; + } + + return $listed; + + }//end listProfiles() + + /** + * Whether an id names a set this app can actually import. + * + * @param string $profileId The id to test. + * + * @return boolean True when the id is importable. + */ + public function isKnown(string $profileId): bool { + if ($profileId === self::GENERATED_PROFILE) { + return $this->demoData->isAvailable(); + } + + foreach ($this->listProfiles() as $profile) { + if ($profile['id'] === $profileId) { + return true; + } + } + + return false; + + }//end isKnown() + + /** + * Import one example set. + * + * 🔴 THROWS RATHER THAN RETURNING A QUIET FAILURE. An operator just asked for + * this, so "nothing happened" must not be presentable as success. + * + * Safe to run more than once: OpenRegister's seed import matches an existing + * object by slug before it creates one, so a repeat adds nothing. + * + * @param string $profileId The set to import. + * + * @return array{objects: integer, profile: string} What was imported. + * + * @throws RuntimeException When the id is unknown or OpenRegister is absent. + * + * @spec openspec/changes/seed-profiles/specs/seed-profiles/spec.md#requirement-import-one-example-set + */ + public function install(string $profileId): array { + if ($profileId === self::GENERATED_PROFILE) { + $imported = $this->demoData->install(); + return [ + 'objects' => (int)($imported['objects'] ?? 0), + 'profile' => $profileId, + ]; + } + + $path = $this->pathFor(profileId: $profileId); + if ($path === null) { + throw new RuntimeException('No example set is called "' . $profileId . '".'); + } + + $data = $this->readDescriptor(path: $path); + + $objects = 0; + $seeded = ($data['x-openregister']['seedData']['objects'] ?? []); + if (is_array($seeded) === true) { + foreach ($seeded as $forSchema) { + $objects += count((array)$forSchema); + } + } + + $this->configurationService()->importFromApp( + appId: Application::APP_ID . '.profile.' . $profileId, + data: $data, + version: $this->appManager->getAppVersion(Application::APP_ID), + force: true + ); + + $this->logger->info( + '[SeedProfileService] imported example set "' . $profileId . '": ' . $objects . ' object(s).', + ['app' => Application::APP_ID] + ); + + return [ + 'objects' => $objects, + 'profile' => $profileId, + ]; + + }//end install() + + /** + * Absolute paths of the shipped descriptors. + * + * @return array The paths, sorted. + */ + private function descriptorFiles(): array { + $dir = ($this->appManager->getAppPath(Application::APP_ID) . self::PROFILE_DIR); + if (is_dir($dir) === false) { + return []; + } + + $files = glob($dir . '/*.json'); + if ($files === false) { + return []; + } + + sort($files); + + return $files; + + }//end descriptorFiles() + + /** + * The descriptor path for one id, or null when no file declares it. + * + * 🔴 RESOLVED BY READING THE FILES, NEVER BY CONCATENATING THE ID INTO A + * PATH. The id arrives from an HTTP request; building `profiles/$id.json` + * from it would make `../../config/config` a readable file name. + * + * @param string $profileId The id to resolve. + * + * @return string|null The path, or null. + */ + private function pathFor(string $profileId): ?string { + foreach ($this->descriptorFiles() as $file) { + $meta = $this->readProfileMeta(path: $file); + if ($meta !== null && $meta['id'] === $profileId) { + return $file; + } + } + + return null; + + }//end pathFor() + + /** + * The `x-openregister.profile` block of one descriptor. + * + * A malformed or non-profile file is SKIPPED rather than fatal: one bad file + * must not make every other example set unreachable. + * + * @param string $path The descriptor path. + * + * @return array{id: string, label: string, description: string, order: integer, objectCount: integer}|null The block, or null. + */ + private function readProfileMeta(string $path): ?array { + $raw = file_get_contents($path); + if ($raw === false) { + $this->logger->warning('[SeedProfileService] unreadable example set: ' . basename($path)); + return null; + } + + $data = json_decode($raw, true); + if (is_array($data) === false) { + $this->logger->warning('[SeedProfileService] malformed example set: ' . basename($path)); + return null; + } + + $profile = ($data['x-openregister']['profile'] ?? null); + if (is_array($profile) === false || is_string(($profile['id'] ?? null)) === false) { + $this->logger->warning('[SeedProfileService] example set declares no profile block: ' . basename($path)); + return null; + } + + return [ + 'id' => (string)$profile['id'], + 'label' => (string)($profile['label'] ?? $profile['id']), + 'description' => (string)($profile['description'] ?? ''), + 'order' => (int)($profile['order'] ?? 99), + 'objectCount' => (int)($profile['objectCount'] ?? 0), + ]; + + }//end readProfileMeta() + + /** + * Read and decode one descriptor, or throw. + * + * @param string $path The descriptor path. + * + * @return array The decoded descriptor. + * + * @throws RuntimeException When the file cannot be read or parsed. + */ + private function readDescriptor(string $path): array { + $raw = file_get_contents($path); + if ($raw === false) { + throw new RuntimeException('The example set could not be read: ' . basename($path)); + } + + $data = json_decode($raw, true); + if (is_array($data) === false) { + throw new RuntimeException('The example set is not valid JSON: ' . basename($path)); + } + + return $data; + + }//end readDescriptor() + + /** + * OpenRegister's configuration importer. + * + * 🔴 THE RETURN TYPE IS `object`, NOT THE CLASS, AND THAT IS THE POINT. + * Naming a class from an OPTIONAL app in a native return type makes PHP + * resolve it whenever this method returns, so on an instance without + * OpenRegister the failure is a TypeError about a class nobody mentioned + * instead of the RuntimeException below that names the missing app. + * + * @return object The importer, an OCA\OpenRegister\Service\ConfigurationService. + * + * @psalm-return \OCA\OpenRegister\Service\ConfigurationService + * + * @throws RuntimeException When OpenRegister is not installed. + */ + private function configurationService(): object { + if (in_array('openregister', $this->appManager->getInstalledApps(), true) === false) { + throw new RuntimeException('Example data needs OpenRegister, which is not installed.'); + } + + return $this->container->get('OCA\OpenRegister\Service\ConfigurationService'); + + }//end configurationService() +}//end class diff --git a/lib/Settings/decidesk_register.json b/lib/Settings/decidesk_register.json index 52716a207..cd686a42b 100644 --- a/lib/Settings/decidesk_register.json +++ b/lib/Settings/decidesk_register.json @@ -48,1443 +48,7 @@ } ] }, - "seedData": { - "description": "Demonstration seed objects for governance bodies, meetings, decisions, voting, and evaluations. Planted by OpenRegister via the x-openregister.seedData import path (ImportHandler::importSeedData).", - "objects": { - "person": [ - { - "slug": "femke-halsema", - "name": "Femke Halsema", - "givenName": "Femke", - "familyName": "Halsema", - "gender": "female", - "email": "f.halsema@amsterdam.nl", - "biography": "Burgemeester van Amsterdam, voorzitter van de gemeenteraad." - }, - { - "slug": "marie-janssen", - "name": "Marie Janssen", - "givenName": "Marie", - "familyName": "Janssen", - "gender": "female", - "email": "m.janssen@amsterdam.nl", - "biography": "Raadslid en lid van de VNG-ledenraad." - }, - { - "slug": "jan-de-vries", - "name": "Jan de Vries", - "givenName": "Jan", - "familyName": "de Vries", - "gender": "male", - "email": "j.devries@waterschap.nl", - "biography": "Secretaris / griffier." - }, - { - "slug": "janneke-de-bruin", - "name": "Janneke de Bruin", - "givenName": "Janneke", - "familyName": "de Bruin", - "gender": "female", - "email": "j.debruin@acme.example", - "biography": "Voorzitter Raad van Commissarissen.", - "nationality": "NL" - }, - { - "slug": "mark-van-den-berg", - "name": "Mark van den Berg", - "givenName": "Mark", - "familyName": "van den Berg", - "gender": "male", - "email": "m.vandenberg@acme.example", - "biography": "Lid Raad van Bestuur.", - "nationality": "NL" - } - ], - "post": [ - { - "slug": "post-voorzitter-amsterdam", - "label": "Voorzitter gemeenteraad", - "role": "chair", - "startDate": "2018-05-30T00:00:00Z", - "governanceBody": "gemeenteraad-amsterdam" - }, - { - "slug": "post-griffier-amsterdam", - "label": "Raadsgriffier", - "role": "secretary", - "startDate": "2021-01-15T00:00:00Z", - "governanceBody": "gemeenteraad-amsterdam" - }, - { - "slug": "post-voorzitter-rvc", - "label": "Voorzitter RvC", - "role": "chair", - "startDate": "2022-04-01T00:00:00Z", - "governanceBody": "rvc-waterschap-amstel" - } - ], - "membership": [ - { - "slug": "m-femke-amsterdam", - "role": "chair", - "label": "Voorzitter raad", - "party": "GroenLinks", - "votingWeight": 1, - "startDate": "2018-05-30T00:00:00Z", - "person": "femke-halsema", - "governanceBody": "gemeenteraad-amsterdam", - "post": "post-voorzitter-amsterdam" - }, - { - "slug": "m-marie-amsterdam", - "role": "member", - "label": "Raadslid", - "party": "D66", - "votingWeight": 1, - "startDate": "2022-03-16T00:00:00Z", - "person": "marie-janssen", - "governanceBody": "gemeenteraad-amsterdam" - }, - { - "slug": "m-jan-amstel", - "role": "secretary", - "label": "Raadsgriffier", - "votingWeight": 0, - "startDate": "2021-01-15T00:00:00Z", - "person": "jan-de-vries", - "governanceBody": "rvc-waterschap-amstel", - "post": "post-griffier-amsterdam" - }, - { - "slug": "m-janneke-rvc", - "role": "chair", - "label": "Voorzitter RvC", - "votingWeight": 1, - "startDate": "2022-04-01T00:00:00Z", - "endDate": "2026-04-01T00:00:00Z", - "independenceStatus": "independent", - "otherPositions": [ - "RvC Stedin (vice-voorzitter)", - "Bestuur Stichting Concertgebouw" - ], - "person": "janneke-de-bruin", - "governanceBody": "rvc-waterschap-amstel", - "post": "post-voorzitter-rvc" - }, - { - "slug": "m-mark-rvb", - "role": "member", - "label": "Lid RvB", - "votingWeight": 1, - "startDate": "2020-01-01T00:00:00Z", - "endDate": "2025-12-31T00:00:00Z", - "independenceStatus": "non-independent", - "otherPositions": [ - "Bestuur Branchevereniging Tech NL" - ], - "person": "mark-van-den-berg", - "governanceBody": "rvc-waterschap-amstel" - }, - { - "slug": "m-marie-vng", - "role": "member", - "label": "Lid ledenraad", - "votingWeight": 1, - "startDate": "2024-01-01T00:00:00Z", - "person": "marie-janssen", - "governanceBody": "ledenraad-vng" - }, - { - "slug": "m-marie-groenlinks-fractie", - "role": "member", - "label": "Fractielid", - "party": "GroenLinks", - "votingWeight": 1, - "startDate": "2022-03-16T00:00:00Z", - "person": "marie-janssen", - "governanceBody": "groenlinks-fractie-amsterdam" - } - ], - "contact-detail": [ - { - "slug": "cd-femke-email", - "type": "email", - "value": "f.halsema@amsterdam.nl", - "label": "Werk", - "person": "femke-halsema" - }, - { - "slug": "cd-femke-phone", - "type": "phone", - "value": "+31 20 624 1111", - "label": "Bestuurssecretariaat", - "person": "femke-halsema" - }, - { - "slug": "cd-amsterdam-address", - "type": "address", - "value": "Amstel 1, Amsterdam", - "label": "Stadhuis", - "governanceBody": "gemeenteraad-amsterdam" - } - ], - "governance-body": [ - { - "slug": "gemeenteraad-amsterdam", - "name": "Gemeenteraad Amsterdam", - "bodyType": "legislative", - "domain": "municipality", - "votingDefault": "for-against-abstain", - "termStart": "2022-03-16T00:00:00Z", - "termEnd": "2026-03-15T00:00:00Z" - }, - { - "slug": "rvc-waterschap-amstel", - "name": "Raad van Commissarissen Waterschap Amstel, Gooi en Vecht", - "bodyType": "corporate-board", - "domain": "water-authority", - "votingDefault": "for-against-abstain", - "termStart": "2023-01-01T00:00:00Z", - "termEnd": "2026-12-31T00:00:00Z" - }, - { - "slug": "directieteam-gemeente-utrecht", - "name": "Directieteam Gemeente Utrecht", - "bodyType": "operational", - "domain": "municipality", - "votingDefault": "show-of-hands" - }, - { - "slug": "ledenraad-vng", - "name": "Ledenraad VNG", - "bodyType": "association", - "domain": "association", - "votingDefault": "for-against-abstain", - "termStart": "2024-01-01T00:00:00Z", - "termEnd": "2025-12-31T00:00:00Z" - }, - { - "slug": "auditcommissie-provincie-nh", - "name": "Auditcommissie Provincie Noord-Holland", - "bodyType": "legislative", - "domain": "province", - "votingDefault": "for-against-abstain" - }, - { - "slug": "raad-van-commissarissen-acme-bv", - "name": "Raad van Commissarissen ACME B.V.", - "bodyType": "supervisory-board", - "domain": "corporate", - "votingDefault": "for-against-abstain", - "termStart": "2024-01-01T00:00:00Z", - "termEnd": "2027-12-31T00:00:00Z" - }, - { - "slug": "managementteam-acme-bv", - "name": "Managementteam ACME B.V.", - "bodyType": "operational", - "domain": "corporate", - "votingDefault": "show-of-hands" - }, - { - "slug": "raad-van-bestuur-acme-bv", - "name": "Raad van Bestuur ACME B.V.", - "bodyType": "executive-board", - "domain": "corporate", - "votingDefault": "for-against-abstain", - "termStart": "2024-01-01T00:00:00Z", - "termEnd": "2028-12-31T00:00:00Z" - }, - { - "slug": "groenlinks-fractie-amsterdam", - "name": "GroenLinks-fractie", - "bodyType": "faction", - "domain": "municipality", - "parentBody": "gemeenteraad-amsterdam", - "votingDefault": "for-against-abstain" - }, - { - "slug": "d66-fractie-amsterdam", - "name": "D66-fractie", - "bodyType": "faction", - "domain": "municipality", - "parentBody": "gemeenteraad-amsterdam", - "votingDefault": "for-against-abstain" - }, - { - "slug": "bezwaaradviescommissie-amsterdam", - "name": "Bezwaaradviescommissie Amsterdam", - "bodyType": "advisory-body", - "domain": "municipality", - "statutoryBasis": "Awb 7:13", - "jurisdiction": "Gemeente Amsterdam — algemene bezwaren", - "quorum": 3, - "quorumRule": "majority", - "active": true, - "termStart": "2024-01-01T00:00:00Z", - "termEnd": "2028-01-01T00:00:00Z" - } - ], - "meeting": [ - { - "slug": "raadsvergadering-2025-01-15", - "title": "Raadsvergadering 15 januari 2025", - "meetingType": "regular", - "scheduledDate": "2025-01-15T19:30:00Z", - "endDate": "2025-01-15T23:00:00Z", - "location": "Stadhuis Amsterdam, Raadzaal", - "meetingMode": "hybrid", - "lifecycle": "closed" - }, - { - "slug": "rvc-vergadering-q1-2025", - "title": "RvC Vergadering Q1 2025 — Waterschap", - "meetingType": "regular", - "scheduledDate": "2025-02-05T10:00:00Z", - "endDate": "2025-02-05T13:00:00Z", - "location": "Waternet Kantoor, Amstel 1", - "meetingMode": "in-person", - "lifecycle": "closed" - }, - { - "slug": "directieoverleg-2025-04-14", - "title": "Directieoverleg week 16 — Gemeente Utrecht", - "meetingType": "regular", - "scheduledDate": "2025-04-14T09:00:00Z", - "endDate": "2025-04-14T11:00:00Z", - "location": "Stadskantoor Utrecht, Kamer 3.12", - "meetingMode": "hybrid", - "lifecycle": "draft" - }, - { - "slug": "ledenvergadering-vng-voorjaar-2025", - "title": "Algemene Ledenvergadering VNG — Voorjaar 2025", - "meetingType": "public hearing", - "scheduledDate": "2025-06-18T13:00:00Z", - "endDate": "2025-06-18T17:00:00Z", - "location": "World Forum Den Haag", - "meetingMode": "in-person", - "lifecycle": "scheduled", - "quorumRequired": 50 - }, - { - "slug": "rvc-vergadering-2025-q2", - "title": "RvC-vergadering Q2 2025", - "meetingType": "regular", - "scheduledDate": "2025-04-17T14:00:00Z", - "endDate": "2025-04-17T16:30:00Z", - "location": "ACME B.V. hoofdkantoor, bestuurskamer", - "meetingMode": "hybrid", - "lifecycle": "closed" - } - ], - "participant": [ - { - "slug": "femke-halsema", - "displayName": "Femke Halsema", - "role": "chair", - "email": "f.halsema@amsterdam.nl", - "joinedAt": "2018-05-30T00:00:00Z", - "votingWeight": 1 - }, - { - "slug": "jan-de-vries", - "displayName": "Jan de Vries", - "role": "secretary", - "email": "j.devries@waterschap.nl", - "joinedAt": "2021-01-15T00:00:00Z", - "votingWeight": 1 - }, - { - "slug": "marie-janssen", - "displayName": "Marie Janssen", - "role": "member", - "party": "D66", - "email": "m.janssen@amsterdam.nl", - "joinedAt": "2022-03-16T00:00:00Z", - "votingWeight": 1 - }, - { - "slug": "pieter-bakker", - "displayName": "Pieter Bakker", - "role": "chair", - "email": "p.bakker@utrecht.nl", - "joinedAt": "2020-06-01T00:00:00Z", - "votingWeight": 1 - }, - { - "slug": "ans-rutten", - "displayName": "Ans Rutten", - "role": "observer", - "email": "a.rutten@vng.nl", - "joinedAt": "2024-01-10T00:00:00Z", - "votingWeight": 0 - } - ], - "agenda-item": [ - { - "slug": "opening-raad-2025-01-15", - "title": "Opening vergadering", - "itemType": "informational", - "orderNumber": 1, - "estimatedDuration": 5 - }, - { - "slug": "notulen-2024-12-18", - "title": "Vaststellen notulen vergadering 18 december 2024", - "itemType": "decision", - "orderNumber": 2, - "estimatedDuration": 10, - "isRecurring": true - }, - { - "slug": "jaarrekening-2024", - "title": "Jaarrekening 2024 — ter goedkeuring", - "itemType": "decision", - "orderNumber": 3, - "estimatedDuration": 45, - "description": "Bespreking en vaststelling van de jaarrekening over het boekjaar 2024" - }, - { - "slug": "begroting-2026-bespreking", - "title": "Kadernota begroting 2026", - "itemType": "discussion", - "orderNumber": 4, - "estimatedDuration": 60, - "description": "Eerste bespreking van de financiële kaders voor begrotingsjaar 2026" - }, - { - "slug": "rondvraag", - "title": "Rondvraag", - "itemType": "informational", - "orderNumber": 99, - "estimatedDuration": 10, - "isRecurring": true - } - ], - "voting-round": [ - { - "slug": "stemming-motie-duurzaamheid-2025", - "votingMethod": "for-against-abstain", - "isSecret": false, - "openedAt": "2025-04-10T21:00:00Z", - "closedAt": "2025-04-10T21:05:00Z", - "quorumWith": true, - "result": "adopted", - "votesFor": 28, - "votesAgainst": 3, - "votesAbstain": 2 - }, - { - "slug": "stemming-begroting-2026", - "votingMethod": "for-against-abstain", - "isSecret": false, - "openedAt": "2025-04-10T21:30:00Z", - "closedAt": "2025-04-10T21:38:00Z", - "quorumWith": true, - "result": "adopted", - "votesFor": 25, - "votesAgainst": 6, - "votesAbstain": 2 - }, - { - "slug": "stemming-amendement-a", - "votingMethod": "for-against-abstain", - "isSecret": false, - "openedAt": "2025-04-10T20:55:00Z", - "closedAt": "2025-04-10T21:00:00Z", - "quorumWith": true, - "result": "rejected", - "votesFor": 11, - "votesAgainst": 20, - "votesAbstain": 2 - }, - { - "slug": "stemming-begroting-2027-gemeenteraad", - "votingMethod": "for-against-abstain", - "isSecret": false, - "openedAt": "2026-04-15T21:00:00Z", - "closedAt": "2026-04-15T21:15:00Z", - "quorumWith": true, - "result": "adopted", - "votesFor": 28, - "votesAgainst": 3, - "votesAbstain": 2, - "voteThreshold": "simple-majority", - "abstentionHandling": "exclude", - "decisionStage": "stage-begroting-2027-3-dec" - }, - { - "slug": "stemming-investering-acme-rvb-geheim", - "votingMethod": "for-against-abstain", - "isSecret": true, - "openedAt": "2026-04-18T15:00:00Z", - "closedAt": "2026-04-18T15:20:00Z", - "quorumWith": true, - "result": "adopted", - "votesFor": 3, - "votesAgainst": 0, - "votesAbstain": 0, - "voteThreshold": "simple-majority", - "abstentionHandling": "exclude", - "decisionStage": "stage-investering-acme-2-dec" - } - ], - "vote": [ - { - "slug": "stem-devries-motie-duurzaamheid", - "value": "for", - "weight": 1, - "isProxy": false, - "castAt": "2025-04-10T21:01:00Z" - }, - { - "slug": "stem-bakker-motie-duurzaamheid", - "value": "against", - "weight": 1, - "isProxy": false, - "castAt": "2025-04-10T21:02:00Z" - }, - { - "slug": "stem-elamrani-begroting-2026", - "value": "for", - "weight": 1, - "isProxy": false, - "castAt": "2025-04-10T21:31:00Z" - }, - { - "slug": "stem-proxy-vandam-begroting", - "value": "for", - "weight": 1, - "isProxy": true, - "castAt": "2025-04-10T21:32:00Z" - }, - { - "slug": "stem-femke-begroting-2027", - "value": "for", - "weight": 1, - "isProxy": false, - "castAt": "2026-04-15T21:05:00Z", - "castAs": "in-person", - "votingRound": "stemming-begroting-2027-gemeenteraad", - "participant": "femke-halsema" - }, - { - "slug": "stem-marie-begroting-2027", - "value": "for", - "weight": 1, - "isProxy": false, - "castAt": "2026-04-15T21:06:00Z", - "castAs": "in-person", - "votingRound": "stemming-begroting-2027-gemeenteraad", - "participant": "marie-janssen" - } - ], - "decision": [ - { - "slug": "besluit-begroting-2026", - "decisionType": "meeting-outcome", - "title": "Vaststelling Programmabegroting 2026", - "text": "De gemeenteraad van Westerkwartier stelt de programmabegroting 2026 vast.", - "decisionDate": "2025-04-10T21:38:00Z", - "outcome": "adopted", - "isPublished": "public", - "publishedAt": "2025-04-11T09:00:00Z", - "legalBasis": "Gemeentewet art. 189", - "lifecycle": "enacted", - "enactedAt": "2025-04-11T09:00:00Z" - }, - { - "slug": "besluit-duurzaamheid-2025", - "decisionType": "meeting-outcome", - "title": "Motie Duurzaamheid aangenomen", - "text": "De raad verzoekt het college een plan van aanpak zonnepanelen te presenteren voor 1 januari 2026.", - "decisionDate": "2025-04-10T21:05:00Z", - "outcome": "adopted", - "isPublished": "public", - "publishedAt": "2025-04-11T09:00:00Z", - "lifecycle": "enacted", - "enactedAt": "2025-04-11T09:00:00Z" - }, - { - "slug": "besluit-bestemmingsplan-groningen-noord", - "decisionType": "meeting-outcome", - "title": "Vaststelling bestemmingsplan Groningen-Noord", - "text": "De raad stelt het bestemmingsplan Groningen-Noord ongewijzigd vast.", - "decisionDate": "2025-03-27T20:45:00Z", - "outcome": "adopted", - "isPublished": "internal", - "legalBasis": "Wet ruimtelijke ordening art. 3.1", - "lifecycle": "decided" - }, - { - "slug": "besluit-woningbouwplan-oost", - "decisionType": "meeting-outcome", - "title": "Vaststelling Woningbouwplan Oost 2025-2030", - "text": "De gemeenteraad van Westerkwartier stelt het Woningbouwplan Oost 2025-2030 vast en machtigt het college tot uitvoering conform bijgaande planning en budgettering.", - "decisionDate": "2025-03-20T21:15:00Z", - "outcome": "adopted", - "isPublished": "public", - "publishedAt": "2025-03-21T09:00:00Z", - "legalBasis": "Wet ruimtelijke ordening art. 3.1", - "lifecycle": "enacted", - "enactedAt": "2025-03-21T09:00:00Z" - }, - { - "slug": "besluit-duurzaamheidsagenda-2026", - "decisionType": "meeting-outcome", - "title": "Vaststelling Duurzaamheidsagenda 2026", - "text": "De raad stelt de Duurzaamheidsagenda Westerkwartier 2026 vast en stelt €200.000 beschikbaar voor uitvoering van de daarin opgenomen maatregelen.", - "decisionDate": "2025-03-20T20:45:00Z", - "outcome": "adopted", - "isPublished": "public", - "publishedAt": "2025-03-21T09:00:00Z", - "legalBasis": "Gemeentewet art. 147", - "lifecycle": "enacted", - "enactedAt": "2025-03-21T09:00:00Z" - }, - { - "slug": "besluit-bezwaar-kapvergunning", - "decisionType": "meeting-outcome", - "title": "Besluit op bezwaar kapvergunning Dorpsstraat 12", - "text": "De gemeenteraad verklaart het bezwaar van de bewonersvereniging gegrond en herroept de verleende kapvergunning voor de eik aan Dorpsstraat 12.", - "decisionDate": "2025-04-01T14:30:00Z", - "outcome": "adopted", - "isPublished": "confidential", - "legalBasis": "Algemene wet bestuursrecht art. 7:11", - "lifecycle": "decided" - }, - { - "slug": "besluit-amendement-cultuursubsidie-afgewezen", - "decisionType": "meeting-outcome", - "title": "Amendement verhoging cultuursubsidie — niet aanvaard", - "text": "Het amendement tot verhoging van het cultuursubsidiebudget 2026 met €75.000 wordt niet aanvaard.", - "decisionDate": "2025-04-10T21:00:00Z", - "outcome": "rejected", - "isPublished": "internal", - "lifecycle": "decided" - }, - { - "slug": "besluit-fusie-dorpsraden", - "decisionType": "meeting-outcome", - "title": "Instemming fusie dorpsraden Noord en Oost per 1 januari 2026", - "text": "De raad stemt in met de samenvoeging van dorpsraad Noord en dorpsraad Oost tot één dorpsraad Noord-Oost, ingaande 1 januari 2026.", - "decisionDate": "2025-04-10T20:30:00Z", - "outcome": "adopted", - "isPublished": "public", - "publishedAt": "2025-04-11T08:30:00Z", - "lifecycle": "enacted", - "enactedAt": "2025-04-11T08:30:00Z" - }, - { - "slug": "motie-duurzaamheid-2025", - "decisionType": "motion", - "title": "Motie Duurzaamheid: zonnepanelen op gemeentelijke daken", - "text": "De raad verzoekt het college om voor 1 januari 2026 een concreet plan van aanpak op te stellen voor de plaatsing van zonnepanelen op alle gemeentelijke daken, inclusief een kostenraming en tijdlijn.", - "motionType": "motion", - "proposer": "Roos de Vries", - "lifecycle": "decided", - "outcome": "adopted", - "isPublished": "public", - "submittedAt": "2025-04-10T19:00:00Z", - "decisionDate": "2025-04-10T21:10:00Z" - }, - { - "slug": "motie-woonlasten-2025", - "decisionType": "motion", - "title": "Motie Woonlasten verlagen", - "text": "De raad verzoekt het college de gemeentelijke woonlasten voor 2027 niet verder te verhogen dan de inflatiecorrectie en daartoe bij de Kadernota een dekkingsvoorstel voor te leggen.", - "motionType": "motion", - "proposer": "Jan de Boer", - "lifecycle": "voting", - "isPublished": "public" - }, - { - "slug": "amendement-cultuursubsidie", - "decisionType": "amendment", - "title": "Amendement Cultuursubsidie verhogen", - "text": "De raad besluit post 6.1 (cultuursubsidies) in de programmabegroting te verhogen met €50.000, ten laste van de post onvoorzien.", - "proposer": "Fatima El-Amrani", - "proposedText": "Verhoog post 6.1 met €50.000", - "lifecycle": "decided", - "outcome": "adopted", - "decisionDate": "2025-04-10T21:05:00Z", - "isPublished": "public", - "amends": "motie-duurzaamheid-2025" - }, - { - "slug": "r-2025-001-goedkeuring-jaarrekening", - "decisionType": "resolution", - "title": "Goedkeuring jaarrekening 2024", - "text": "De RvC verleent goedkeuring aan de jaarrekening 2024.", - "resolutionNumber": "R-2025-001", - "voteType": "named", - "voteThreshold": "simple-majority", - "legalBasis": "art. 2:101 BW", - "lifecycle": "enacted", - "outcome": "adopted", - "decisionDate": "2025-05-14T10:30:00Z", - "isPublished": "internal" - }, - { - "slug": "r-2025-002-benoeming-cfo", - "decisionType": "resolution", - "title": "Benoeming CFO", - "text": "De RvC benoemt met ingang van 1 juli 2025 mevrouw A. Jansen tot Chief Financial Officer van de vennootschap.", - "resolutionNumber": "R-2025-002", - "voteType": "anonymous", - "voteThreshold": "simple-majority", - "lifecycle": "enacted", - "outcome": "adopted", - "decisionDate": "2025-05-14T11:15:00Z", - "isPublished": "confidential" - }, - { - "slug": "contract-schoonmaak-2026", - "decisionType": "contract", - "title": "Gunning schoonmaakcontract 2026", - "text": "Het MT gunt het schoonmaakcontract aan Leverancier X.", - "legalBasis": "Aanbestedingswet 2012", - "lifecycle": "decided", - "outcome": "adopted", - "decisionDate": "2026-01-22T14:00:00Z", - "isPublished": "confidential" - }, - { - "slug": "besluit-benoeming-penningmeester", - "decisionType": "appointment", - "title": "Benoeming penningmeester", - "text": "De algemene ledenvergadering benoemt de heer K. de Wit tot penningmeester van de vereniging voor een termijn van drie jaar.", - "lifecycle": "enacted", - "outcome": "adopted", - "decisionDate": "2026-02-05T20:15:00Z", - "isPublished": "internal" - }, - { - "slug": "benoeming-lid-auditcommissie", - "decisionType": "appointment", - "title": "Benoeming lid auditcommissie", - "text": "Voordracht van mevrouw M. Janssen als lid van de auditcommissie, vanwege gewenste financiële expertise.", - "lifecycle": "proposed", - "targetBody": "auditcommissie-provincie-nh", - "targetPosts": [], - "targetRole": "member", - "candidates": [ - { - "person": "marie-janssen", - "notes": "Financiële expertise gewenst in de auditcommissie." - } - ], - "nominatingParty": { - "type": "politicalGroup", - "name": "D66" - }, - "appointedMemberships": [], - "isPublished": "internal" - }, - { - "slug": "benoeming-lid-rvc-acme-van-duin", - "decisionType": "appointment", - "title": "Benoeming lid Raad van Commissarissen ACME B.V.", - "text": "Voordracht van mevrouw J. van Duin (externe werving) als lid van de Raad van Commissarissen, conform profielschets — herbenoeming van de huidige commissaris was niet mogelijk op grond van het rooster van aftreden.", - "lifecycle": "enacted", - "outcome": "adopted", - "decisionDate": "2026-04-10T19:00:00Z", - "targetBody": "raad-van-commissarissen-acme-bv", - "targetPosts": [], - "targetRole": "member", - "candidates": [ - { - "externalName": "Mw. J. van Duin", - "notes": "Externe werving; nog geen Person-registratie — wordt na benoeming aangemaakt." - } - ], - "nominatingParty": { - "type": "body", - "name": "Raad van Commissarissen (coöptatie-voordracht)" - }, - "appointedMemberships": [], - "isPublished": "internal" - }, - { - "slug": "benoeming-voorzitter-auditcommissie-ingetrokken", - "decisionType": "appointment", - "title": "Benoeming voorzitter auditcommissie (ingetrokken)", - "text": "Voordracht van de heer K. Bakker als voorzitter van de auditcommissie; kandidaat heeft zich teruggetrokken voor behandeling.", - "lifecycle": "withdrawn", - "targetBody": "auditcommissie-provincie-nh", - "targetPosts": [], - "targetRole": "chair", - "candidates": [ - { - "externalName": "K. Bakker", - "notes": "Kandidaat trekt zich terug voor behandeling." - } - ], - "nominatingParty": { - "type": "politicalGroup", - "name": "GroenLinks" - }, - "appointedMemberships": [], - "isPublished": "internal" - }, - { - "slug": "mt-go-nogo-zonnepark", - "decisionType": "management-point", - "title": "Go/No-go zonnepark fase 2", - "text": "Het MT besluit fase 2 van het zonnepark vrij te geven voor realisatie, onder voorbehoud van de definitieve netaansluiting.", - "lifecycle": "decided", - "outcome": "adopted", - "decisionDate": "2026-03-03T09:45:00Z", - "isPublished": "internal" - }, - { - "slug": "beleid-thuiswerkregeling", - "decisionType": "policy", - "title": "Vaststelling thuiswerkregeling", - "text": "De organisatie stelt de thuiswerkregeling 2026 vast: standaard twee thuiswerkdagen per week, met een vergoeding conform de fiscale onbelaste norm.", - "lifecycle": "enacted", - "outcome": "adopted", - "decisionDate": "2026-03-18T11:00:00Z", - "isPublished": "public" - }, - { - "slug": "besluit-begroting-2027", - "decisionType": "meeting-outcome", - "title": "Vaststelling Programmabegroting 2027", - "text": "De gemeenteraad stelt de programmabegroting 2027 vast conform het raadsvoorstel van het college.", - "decisionDate": "2026-04-15T19:30:00Z", - "outcome": "adopted", - "isPublished": "public", - "legalBasis": "Gemeentewet art. 189", - "lifecycle": "enacted", - "enactedAt": "2026-04-16T09:00:00Z", - "supersedes": [ - "besluit-begroting-2026" - ], - "route": [ - "stage-begroting-2027-1-prep", - "stage-begroting-2027-2-adv", - "stage-begroting-2027-3-dec" - ] - }, - { - "slug": "besluit-investering-acme", - "decisionType": "management-point", - "title": "Investeringsbesluit Datacenteruitbreiding ACME B.V.", - "text": "Het MT besluit tot investering in uitbreiding van het datacentercapaciteit met €2,4M conform de goedgekeurde businesscase.", - "decisionDate": "2026-05-01T10:00:00Z", - "outcome": "adopted", - "isPublished": "confidential", - "lifecycle": "decided", - "route": [ - "stage-investering-acme-1-prep", - "stage-investering-acme-2-dec", - "stage-investering-acme-3-rat" - ] - } - ], - "decision-stage": [ - { - "slug": "stage-begroting-2027-1-prep", - "sequence": 1, - "stageType": "preparatory", - "status": "decided", - "outcome": "adopted", - "decidedAt": "2026-03-02T14:00:00Z", - "method": "manual", - "decisionMakerType": "body", - "label": "Voorbereiding & vaststelling concept", - "note": "Concept vastgesteld door het directieteam. Doorgestuurd naar de commissie.", - "decision": "besluit-begroting-2027", - "assignedBody": "directieteam-gemeente-utrecht" - }, - { - "slug": "stage-begroting-2027-2-adv", - "sequence": 2, - "stageType": "advisory", - "status": "decided", - "outcome": "advised", - "decidedAt": "2026-03-20T17:30:00Z", - "method": "advice", - "decisionMakerType": "person", - "label": "Advies raadscommissie", - "note": "Commissie adviseert de raad de begroting ongewijzigd vast te stellen.", - "decision": "besluit-begroting-2027", - "assignedPerson": "femke-halsema" - }, - { - "slug": "stage-begroting-2027-3-dec", - "sequence": 3, - "stageType": "decisive", - "status": "decided", - "outcome": "adopted", - "decidedAt": "2026-04-15T21:30:00Z", - "method": "vote", - "decisionMakerType": "body", - "label": "Besluit gemeenteraad", - "decision": "besluit-begroting-2027", - "assignedBody": "gemeenteraad-amsterdam", - "votingRound": "stemming-begroting-2027-gemeenteraad" - }, - { - "slug": "stage-investering-acme-1-prep", - "sequence": 1, - "stageType": "preparatory", - "status": "decided", - "outcome": "adopted", - "decidedAt": "2026-04-05T11:00:00Z", - "method": "chair-register", - "decisionMakerType": "body", - "label": "MT-voorbereiding investering", - "note": "Businesscase goedgekeurd door MT-voorzitter.", - "decision": "besluit-investering-acme", - "assignedBody": "managementteam-acme-bv", - "registeredBy": "mark-van-den-berg" - }, - { - "slug": "stage-investering-acme-2-dec", - "sequence": 2, - "stageType": "decisive", - "status": "decided", - "outcome": "adopted", - "decidedAt": "2026-04-18T15:30:00Z", - "method": "vote", - "decisionMakerType": "body", - "label": "Besluit Raad van Bestuur", - "note": "Investeringsbesluit aangenomen — geheime stemming, unanime uitkomst.", - "decision": "besluit-investering-acme", - "assignedBody": "raad-van-bestuur-acme-bv", - "votingRound": "stemming-investering-acme-rvb-geheim" - }, - { - "slug": "stage-investering-acme-3-rat", - "sequence": 3, - "stageType": "ratifying", - "status": "decided", - "outcome": "adopted", - "decidedAt": "2026-05-01T09:15:00Z", - "method": "signature", - "decisionMakerType": "body", - "label": "Goedkeuring Raad van Commissarissen — eIDAS ondertekening", - "note": "RvC-besluit bekrachtigd via QES-handtekeningen. Notulen ondertekend door voorzitter en secretaris.", - "decision": "besluit-investering-acme", - "assignedBody": "raad-van-commissarissen-acme-bv", - "signedDocument": "notulen-rvc-investering-acme-signed" - } - ], - "action-item": [ - { - "slug": "actie-plan-zonnepanelen", - "title": "Plan van aanpak zonnepanelen gemeentelijke gebouwen opstellen", - "description": "College presenteert plan voor 1 januari 2026 conform aangenomen motie.", - "assignee": "Wethouder Duurzaamheid", - "dueDate": "2026-01-01T00:00:00Z", - "taskStatus": "open" - }, - { - "slug": "actie-communicatie-begroting-2026", - "title": "Begroting 2026 communiceren naar inwoners", - "assignee": "Communicatieafdeling", - "dueDate": "2025-05-01T00:00:00Z", - "taskStatus": "completed", - "completedAt": "2025-04-25T14:30:00Z" - }, - { - "slug": "actie-bestemmingsplan-publiceren", - "title": "Bestemmingsplan Groningen-Noord publiceren op ruimtelijkeplannen.nl", - "assignee": "Ruimtelijke Ordening", - "dueDate": "2025-04-10T00:00:00Z", - "taskStatus": "overdue" - }, - { - "slug": "actie-woningbouw-uitvoeringsplan", - "title": "Uitvoeringsplan Woningbouwplan Oost opstellen", - "description": "College stelt uitvoeringsplan op inclusief fasering, budgetten en planning.", - "assignee": "Wethouder Wonen", - "dueDate": "2025-07-01T00:00:00Z", - "taskStatus": "in-progress" - }, - { - "slug": "actie-duurzaamheid-offerteverzoek", - "title": "Offerteverzoek zonnepanelen gemeentelijke gebouwen uitzetten", - "description": "Inkoopteam vraagt offertes op bij minimaal 3 leveranciers conform gemeentelijk aanbestedingsbeleid.", - "assignee": "Inkoopcoördinator", - "dueDate": "2025-05-15T00:00:00Z", - "taskStatus": "completed", - "completedAt": "2025-05-10T16:00:00Z" - }, - { - "slug": "actie-notulen-distribueren", - "title": "Definitieve notulen raadsvergadering 20 maart distribueren", - "description": "Griffier verstuurt vastgestelde notulen aan alle raadsleden en publiceert op gemeentelijke website.", - "assignee": "Griffier", - "dueDate": "2025-04-11T00:00:00Z", - "taskStatus": "completed", - "completedAt": "2025-04-11T09:30:00Z" - }, - { - "slug": "actie-besluiten-ori-publicatie", - "title": "Besluiten raadsvergadering publiceren via ORI-koppeling", - "description": "Informatiemanager controleert ORI-export en bevestigt succesvolle aanlevering bij PLOOI.", - "assignee": "Informatiemanager", - "dueDate": "2025-03-22T00:00:00Z", - "taskStatus": "overdue" - }, - { - "slug": "actie-fusie-dorpsraden-convenant", - "title": "Convenant fusie dorpsraden Noord en Oost opstellen en laten ondertekenen", - "description": "Gemeentelijke contactpersoon stelt convenant op in samenspraak met beide dorpsraden.", - "assignee": "Beleidsmedewerker Participatie", - "dueDate": "2025-10-01T00:00:00Z", - "taskStatus": "open" - } - ], - "minutes": [ - { - "slug": "notulen-raad-2025-04-10", - "title": "Notulen Raadsvergadering 10 april 2025", - "lifecycle": "approved", - "content": "De vergadering wordt geopend door de voorzitter om 19:30 uur...", - "approvedAt": "2025-05-08T19:45:00Z", - "signedBy": [ - "Roos de Vries", - "Jan Bakker" - ], - "version": 2 - }, - { - "slug": "notulen-commissie-ruimte-2025-03-04", - "title": "Notulen Commissievergadering Ruimte & Wonen 4 maart 2025", - "lifecycle": "signed", - "content": "De commissievergadering Ruimte & Wonen wordt geopend...", - "approvedAt": "2025-04-01T10:00:00Z", - "signedBy": [ - "Henk Bakker" - ], - "version": 1 - }, - { - "slug": "notulen-ab-waterschap-2025-02-13", - "title": "Notulen AB Waterschap Aa en Maas 13 februari 2025", - "lifecycle": "draft", - "version": 1 - }, - { - "slug": "notulen-raad-2025-03-20", - "title": "Notulen Gemeenteraadsvergadering 20 maart 2025", - "lifecycle": "published", - "content": "De vergadering wordt geopend door de voorzitter om 19:30 uur. Aanwezig: 33 van 37 raadsleden. Punt 5 — Woningbouwplan Oost 2025-2030: na bespreking wordt het plan aangenomen met 30 stemmen voor en 3 tegen.", - "approvedAt": "2025-04-10T19:45:00Z", - "signedBy": [ - "Roos de Vries", - "Jan Bakker" - ], - "version": 2 - }, - { - "slug": "notulen-commissie-wonen-2025-04-01", - "title": "Notulen Commissievergadering Wonen & Ruimte 1 april 2025", - "lifecycle": "signed", - "content": "Aanvang: 19:00 uur. Voorzitter: Henk Bakker. Commissieleden aanwezig: 7 van 9. Agendapunt 2 — bestemmingsplan Groningen-Noord: de commissie adviseert de raad het plan ongewijzigd vast te stellen.", - "approvedAt": "2025-04-15T10:00:00Z", - "signedBy": [ - "Henk Bakker" - ], - "version": 1 - }, - { - "slug": "notulen-ab-waterschap-2025-04-10", - "title": "Notulen Vergadering Algemeen Bestuur Waterschap Aa en Maas 10 april 2025", - "lifecycle": "review", - "content": "Concept-verslag ter vaststelling. De vergadering van het Algemeen Bestuur wordt geopend door de dijkgraaf om 14:00 uur.", - "version": 1 - }, - { - "slug": "notulen-directieoverleg-2025-04-14", - "title": "Verslag Directieoverleg Gemeente Utrecht 14 april 2025", - "lifecycle": "draft", - "version": 1 - }, - { - "slug": "notulen-rvc-2025-q2", - "title": "Notulen RvC-vergadering Q2 2025", - "lifecycle": "approved", - "content": "De voorzitter van de Raad van Commissarissen opent de vergadering om 14:00 uur...", - "approvedAt": "2025-05-15T10:00:00Z", - "signedBy": [ - "Voorzitter RvC", - "Secretaris" - ], - "version": 1 - } - ], - "digital-document": [ - { - "slug": "notulen-rvc-investering-acme-signed", - "name": "Ondertekende notulen RvC — Investeringsbesluit Datacenteruitbreiding ACME B.V.", - "documentType": "signed-minutes", - "description": "QES-ondertekende notulen van de RvC-vergadering betreffende het investeringsbesluit datacenteruitbreiding. Ondertekend door voorzitter en secretaris via eIDAS-gekwalificeerde elektronische handtekening.", - "encodingFormat": "application/pdf", - "contentSize": "1.2 MB" - } - ], - "engagement-record": [ - { - "slug": "engagement-raadsvergadering-jan-de-boer", - "meeting": "raadsvergadering-2025-01-15", - "participant": "jan-de-boer", - "speeches": [ - { - "duration": 180 - } - ], - "questionsRaised": [ - { - "text": "Vraag over begroting" - } - ], - "topicsSuggested": [], - "speakingDuration": 180, - "engagementScore": 15 - }, - { - "slug": "engagement-raadsvergadering-fatima", - "meeting": "raadsvergadering-2025-01-15", - "participant": "fatima-el-idrissi", - "speeches": [ - { - "duration": 300 - }, - { - "duration": 120 - } - ], - "questionsRaised": [ - { - "text": "Vraag over klimaatbeleid" - } - ], - "topicsSuggested": [ - { - "title": "Woningbouw versnellen" - } - ], - "speakingDuration": 420, - "engagementScore": 32 - }, - { - "slug": "engagement-rvc-q1-pieter", - "meeting": "rvc-vergadering-q1-2025", - "participant": "pieter-van-den-berg", - "speeches": [], - "questionsRaised": [], - "topicsSuggested": [ - { - "title": "Duurzaamheidsrapportage" - } - ], - "speakingDuration": 0, - "engagementScore": 6 - } - ], - "conflict-of-interest": [ - { - "slug": "coi-ben-r002", - "boardMember": "ben-okonkwo-rvc-acme", - "agendaItem": "r-2025-002-appointment-cfo", - "declarationType": "personal-relationship", - "description": "Familierelatie met kandidaat-CFO.", - "severity": "material", - "actionTaken": "recused-from-vote", - "declarationTimestamp": "2025-03-12T16:50:00Z" - }, - { - "slug": "coi-petra-r005", - "boardMember": "petra-jansen-rvc-acme", - "agendaItem": "r-2025-005-policy-procurement", - "declarationType": "competing-business", - "description": "Bestuurslid bij Stichting Procurement Excellence.", - "severity": "non-material", - "actionTaken": "disclosed-and-participated", - "declarationTimestamp": "2025-03-12T17:10:00Z" - }, - { - "slug": "coi-mark-r003", - "boardMember": "mark-van-den-berg-rvb-acme", - "agendaItem": "r-2025-003-financial-acquisition", - "declarationType": "financial-interest", - "description": "Indirect aandelenbelang in target via family-trust (<1%).", - "severity": "non-material", - "actionTaken": "disclosed-and-participated", - "declarationTimestamp": "2025-04-22T17:45:00Z" - }, - { - "slug": "coi-sandra-r004", - "boardMember": "sandra-yilmaz-rvb-acme", - "declarationType": "prior-involvement", - "description": "Eerder consultancy-werk voor ESG-adviseur die de strategie heeft opgesteld.", - "severity": "non-material", - "actionTaken": "no-action-needed", - "declarationTimestamp": "2025-04-22T17:30:00Z" - }, - { - "slug": "coi-david-r008", - "boardMember": "david-cohen-audit-noord", - "agendaItem": "r-2025-008-audit-charter", - "declarationType": "none", - "actionTaken": "no-action-needed", - "declarationTimestamp": "2025-06-04T10:05:00Z" - }, - { - "slug": "coi-rachid-q3", - "boardMember": "rachid-el-amrani-audit-noord", - "declarationType": "competing-business", - "description": "Tweede bestuursfunctie bij vergelijkbare wooncorporatie.", - "severity": "material", - "actionTaken": "recused-from-discussion", - "declarationTimestamp": "2025-06-04T10:10:00Z" - }, - { - "slug": "coi-hannah-r002", - "boardMember": "hannah-stein-rvc-acme", - "agendaItem": "r-2025-002-appointment-cfo", - "declarationType": "none", - "actionTaken": "no-action-needed", - "declarationTimestamp": "2025-03-12T16:48:00Z" - }, - { - "slug": "coi-klaas-strategy", - "boardMember": "klaas-mulder-rvc-acme", - "declarationType": "prior-involvement", - "description": "Voormalig CEO van strategieadviseur die de strategiedag faciliteert.", - "severity": "non-material", - "actionTaken": "disclosed-and-participated", - "declarationTimestamp": "2025-09-18T09:05:00Z" - } - ], - "evaluation-template": [ - { - "slug": "template-bestuurlijke-effectiviteit", - "title": "Board effectiveness self-evaluation (NL Corporate Governance Code)", - "description": "Default reusable annual board self-evaluation (zelfevaluatie) covering the five standard effectiveness dimensions. Editable per body.", - "dimensions": [ - "strategy-and-oversight", - "board-composition", - "board-dynamics", - "information-quality", - "chair-effectiveness" - ], - "questions": [ - { - "id": "q-strategy-likert", - "dimension": "strategy-and-oversight", - "prompt": "The board sets clear strategic direction and exercises effective oversight of management.", - "type": "likert", - "scaleMin": 1, - "scaleMax": 5 - }, - { - "id": "q-strategy-text", - "dimension": "strategy-and-oversight", - "prompt": "What would most improve the board's strategic oversight?", - "type": "free-text" - }, - { - "id": "q-composition-likert", - "dimension": "board-composition", - "prompt": "The board's composition (skills, diversity, independence) matches the organisation's needs.", - "type": "likert", - "scaleMin": 1, - "scaleMax": 5 - }, - { - "id": "q-composition-text", - "dimension": "board-composition", - "prompt": "What skills or perspectives is the board missing?", - "type": "free-text" - }, - { - "id": "q-dynamics-likert", - "dimension": "board-dynamics", - "prompt": "Board discussions are open, constructive, and every member's voice is heard.", - "type": "likert", - "scaleMin": 1, - "scaleMax": 5 - }, - { - "id": "q-dynamics-text", - "dimension": "board-dynamics", - "prompt": "Describe one dynamic that helps or hinders the board's functioning.", - "type": "free-text" - }, - { - "id": "q-information-likert", - "dimension": "information-quality", - "prompt": "The board receives timely, complete, and understandable information ahead of meetings.", - "type": "likert", - "scaleMin": 1, - "scaleMax": 5 - }, - { - "id": "q-information-text", - "dimension": "information-quality", - "prompt": "What information gap most affects the board's decision-making?", - "type": "free-text" - }, - { - "id": "q-chair-likert", - "dimension": "chair-effectiveness", - "prompt": "The chair runs meetings effectively and ensures balanced participation.", - "type": "likert", - "scaleMin": 1, - "scaleMax": 5 - }, - { - "id": "q-chair-text", - "dimension": "chair-effectiveness", - "prompt": "What is one suggestion for the chair?", - "type": "free-text" - } - ] - } - ], - "board-evaluation": [ - { - "slug": "evaluatie-rvc-waterschap-amstel-2025", - "cycleLabel": "2025", - "lifecycle": "closed", - "openedAt": "2025-11-01T09:00:00Z", - "closedAt": "2025-12-20T17:00:00Z", - "invitedMemberCount": 3, - "respondedCount": 2, - "minRespondentThreshold": 3, - "invitedParticipantIds": [ - "jan-de-vries", - "femke-halsema", - "marie-janssen" - ], - "respondedParticipantIds": [ - "jan-de-vries", - "femke-halsema" - ], - "chairUserId": "femke.halsema", - "secretaryUserId": "jan.devries", - "scoreSummary": "{\"overallScore\":3.6,\"respondentCount\":2,\"invitedMemberCount\":3,\"minRespondentThreshold\":3,\"thresholdMet\":false,\"suppressed\":true,\"dimensionScores\":null,\"themes\":null,\"computedAt\":\"2025-12-20T17:05:00Z\"}", - "governanceBody": "rvc-waterschap-amstel", - "template": "template-bestuurlijke-effectiviteit" - }, - { - "slug": "evaluatie-acme-rvc-2026", - "cycleLabel": "2026", - "lifecycle": "open", - "openedAt": "2026-06-01T09:00:00Z", - "invitedMemberCount": 5, - "respondedCount": 2, - "minRespondentThreshold": 3, - "invitedParticipantIds": [ - "acme-lid-1", - "acme-lid-2", - "acme-lid-3", - "acme-lid-4", - "acme-lid-5" - ], - "respondedParticipantIds": [ - "acme-lid-1", - "acme-lid-2" - ], - "chairUserId": "acme.chair", - "secretaryUserId": "acme.secretary", - "governanceBody": "raad-van-commissarissen-acme-bv", - "template": "template-bestuurlijke-effectiviteit" - } - ], - "evaluation-response": [ - { - "slug": "reactie-evaluatie-rvc-waterschap-amstel-2025-a", - "answers": [ - { - "questionId": "q-strategy-likert", - "dimension": "strategy-and-oversight", - "likertValue": 4 - }, - { - "questionId": "q-strategy-text", - "dimension": "strategy-and-oversight", - "freeText": "More time for scenario discussion ahead of budget decisions." - }, - { - "questionId": "q-chair-likert", - "dimension": "chair-effectiveness", - "likertValue": 3 - } - ], - "submittedAt": "2025-12-05T10:12:00Z", - "responseToken": "8f2b6a1e9d3c4f5a7b6e8d1c2a3f4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a", - "boardEvaluation": "evaluatie-rvc-waterschap-amstel-2025" - }, - { - "slug": "reactie-evaluatie-rvc-waterschap-amstel-2025-b", - "answers": [ - { - "questionId": "q-strategy-likert", - "dimension": "strategy-and-oversight", - "likertValue": 4 - }, - { - "questionId": "q-composition-likert", - "dimension": "board-composition", - "likertValue": 3 - }, - { - "questionId": "q-chair-likert", - "dimension": "chair-effectiveness", - "likertValue": 4 - } - ], - "submittedAt": "2025-12-08T14:40:00Z", - "responseToken": "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b", - "boardEvaluation": "evaluatie-rvc-waterschap-amstel-2025" - }, - { - "slug": "reactie-evaluatie-acme-rvc-2026-a", - "answers": [ - { - "questionId": "q-strategy-likert", - "dimension": "strategy-and-oversight", - "likertValue": 5 - }, - { - "questionId": "q-dynamics-text", - "dimension": "board-dynamics", - "freeText": "The board is respectful but could challenge management more." - } - ], - "submittedAt": "2026-06-10T09:30:00Z", - "responseToken": "3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d", - "boardEvaluation": "evaluatie-acme-rvc-2026" - }, - { - "slug": "reactie-evaluatie-acme-rvc-2026-b", - "answers": [ - { - "questionId": "q-strategy-likert", - "dimension": "strategy-and-oversight", - "likertValue": 3 - }, - { - "questionId": "q-information-likert", - "dimension": "information-quality", - "likertValue": 3 - } - ], - "submittedAt": "2026-06-11T11:05:00Z", - "responseToken": "5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f", - "boardEvaluation": "evaluatie-acme-rvc-2026" - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "paths": {}, "components": { diff --git a/lib/Settings/profiles/association.json b/lib/Settings/profiles/association.json new file mode 100644 index 000000000..f2b36c144 --- /dev/null +++ b/lib/Settings/profiles/association.json @@ -0,0 +1,1453 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Decidiq example set: Association or VvE", + "version": "1.0.0", + "description": "A members' meeting with a board. House rules, weighted votes, audit statements and annual accounts." + }, + "x-openregister": { + "type": "profile", + "app": "decidiq", + "profile": { + "id": "association", + "label": "Association or VvE", + "description": "A members' meeting with a board. House rules, weighted votes, audit statements and annual accounts.", + "order": 2, + "objectCount": 56 + }, + "description": "An example set an operator picks in the first-time setup wizard (ADR-042). NEVER imported on install: the register.d fragments declare schemas only, so a bare install has zero objects. Every object carries @self.configuration/register/schema so the import resolves the live decidiq register WITHOUT this descriptor declaring components.registers. That is deliberate and load-bearing: ImportHandler::importRegister() calls setApplication($appId) unconditionally on an existing register, so a descriptor that declared the register would re-point the decidiq register at this profile config id and hydrate over its authorization baseline. Verified on a live instance: importing this shape left application=decidiq, version and authorization byte-identical. Import is idempotent by slug, so loading a profile twice adds nothing. Descriptors live in this SUBDIRECTORY on purpose: RegisterDescriptorService scans lib/Settings/*.json non-recursively and matches descriptors by declared register slug, so four profile files in lib/Settings would collide with each other and with decidesk_register.json.", + "seedData": { + "description": "Example objects for the association or vve set.", + "objects": { + "agenda-item": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "rondvraag", + "title": "Rondvraag", + "itemType": "informational", + "orderNumber": 99, + "estimatedDuration": 10, + "isRecurring": true + } + ], + "cyclus-stap": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "cyclus-stap" + }, + "slug": "begroting-2027-vereniging", + "cyclus": "jaarcyclus-2026-vereniging", + "sequence": 5, + "stepType": "begroting", + "label": "Begroting", + "concernsYear": 2027, + "deliveryDeadline": "2026-10-01", + "decisionMakingBody": "00000000-0000-0000-0000-000000000000", + "handlingDate": "2026-11-25", + "documentSlots": [ + { + "name": "Begroting", + "required": true + } + ], + "status": "planned" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "cyclus-stap" + }, + "slug": "decharge-2025-vereniging", + "cyclus": "jaarcyclus-2026-vereniging", + "sequence": 2, + "stepType": "decharge", + "label": "Decharge bestuur", + "concernsYear": 2025, + "decisionMakingBody": "00000000-0000-0000-0000-000000000000", + "handlingDate": "2026-04-15", + "documentSlots": [], + "status": "planned" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "cyclus-stap" + }, + "slug": "jaarplan-2027-vereniging", + "cyclus": "jaarcyclus-2026-vereniging", + "sequence": 4, + "stepType": "jaarplan", + "label": "Jaarplan", + "concernsYear": 2027, + "deliveryDeadline": "2026-10-01", + "decisionMakingBody": "00000000-0000-0000-0000-000000000000", + "handlingDate": "2026-11-25", + "documentSlots": [ + { + "name": "Jaarplan", + "required": true + } + ], + "status": "planned" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "cyclus-stap" + }, + "slug": "jaarstukken-2025-vereniging", + "cyclus": "jaarcyclus-2026-vereniging", + "sequence": 1, + "stepType": "jaarstukken", + "label": "Jaarstukken", + "concernsYear": 2025, + "deliveryDeadline": "2026-03-01", + "decisionMakingBody": "00000000-0000-0000-0000-000000000000", + "handlingDate": "2026-04-15", + "documentSlots": [ + { + "name": "Jaarrekening", + "required": true, + "file": "Jaarstukken 2025.pdf" + }, + { + "name": "Bestuursverslag", + "required": true + }, + { + "name": "Kascommissieverslag", + "required": true + } + ], + "status": "documents-received" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "cyclus-stap" + }, + "slug": "tussenrapportage-2026-vereniging", + "cyclus": "jaarcyclus-2026-vereniging", + "sequence": 3, + "stepType": "berap", + "label": "Tussenrapportage", + "concernsYear": 2026, + "deliveryDeadline": "2026-05-15", + "decisionMakingBody": "00000000-0000-0000-0000-000000000000", + "handlingDate": "2026-06-20", + "documentSlots": [ + { + "name": "Tussenrapportage", + "required": true + } + ], + "status": "planned" + } + ], + "cyclus-template": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "cyclus-template" + }, + "slug": "association-jaarstukken", + "name": "Verenigings-/jaarstukkencyclus", + "context": "association", + "builtIn": true, + "steps": [ + { + "stepType": "jaarstukken", + "label": "Jaarstukken", + "subjectYearOffset": -1, + "deliveryDeadline": "03-01", + "handlingDate": "04-15", + "documentSlots": [ + { + "name": "Jaarrekening", + "required": true + }, + { + "name": "Bestuursverslag", + "required": true + }, + { + "name": "Kascommissieverslag", + "required": true + } + ] + }, + { + "stepType": "decharge", + "label": "Decharge bestuur", + "subjectYearOffset": -1, + "handlingDate": "04-15", + "documentSlots": [] + }, + { + "stepType": "berap", + "label": "Tussenrapportage", + "subjectYearOffset": 0, + "deliveryDeadline": "05-15", + "handlingDate": "06-20", + "documentSlots": [ + { + "name": "Tussenrapportage", + "required": true + } + ] + }, + { + "stepType": "jaarplan", + "label": "Jaarplan", + "subjectYearOffset": 1, + "deliveryDeadline": "10-01", + "handlingDate": "11-25", + "documentSlots": [ + { + "name": "Jaarplan", + "required": true + } + ] + }, + { + "stepType": "begroting", + "label": "Begroting", + "subjectYearOffset": 1, + "deliveryDeadline": "10-01", + "handlingDate": "11-25", + "documentSlots": [ + { + "name": "Begroting", + "required": true + } + ] + } + ] + } + ], + "decision": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "besluit-benoeming-penningmeester", + "decisionType": "appointment", + "title": "Benoeming penningmeester", + "text": "De algemene ledenvergadering benoemt de heer K. de Wit tot penningmeester van de vereniging voor een termijn van drie jaar.", + "lifecycle": "enacted", + "outcome": "adopted", + "decisionDate": "2026-02-05T20:15:00Z", + "isPublished": "internal" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "besluit-bezwaar-kapvergunning", + "decisionType": "meeting-outcome", + "title": "Besluit op bezwaar kapvergunning Dorpsstraat 12", + "text": "De gemeenteraad verklaart het bezwaar van de bewonersvereniging gegrond en herroept de verleende kapvergunning voor de eik aan Dorpsstraat 12.", + "decisionDate": "2025-04-01T14:30:00Z", + "outcome": "adopted", + "isPublished": "confidential", + "legalBasis": "Algemene wet bestuursrecht art. 7:11", + "lifecycle": "decided" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "besluit-statutenwijziging-vng-2021", + "decisionType": "resolution", + "title": "Besluit statutenwijziging VNG 2021", + "text": "Besluit van de ledenraad van de Vereniging van Nederlandse Gemeenten tot wijziging van de statuten (BW 2:43), in het bijzonder de bevoegdheden van de ledenraad in art. 20.", + "decisionDate": "2021-12-15", + "outcome": "adopted", + "citesGoverningDocuments": [ + { + "document": "statuten-vng", + "article": "art. 20" + } + ] + } + ], + "decision-template": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-template" + }, + "slug": "association-alv", + "name": "Association ALV", + "description": "Standard decision process for a Dutch association general meeting (ALV), BW Book 2.", + "context": "association", + "builtIn": true, + "initialState": "draft", + "stateMachine": { + "states": [ + { + "name": "draft" + }, + { + "name": "proposed" + }, + { + "name": "deliberating" + }, + { + "name": "voting" + }, + { + "name": "decided" + }, + { + "name": "enacted" + }, + { + "name": "archived" + } + ], + "transitions": [ + { + "name": "propose", + "from": "draft", + "to": "proposed" + }, + { + "name": "deliberate", + "from": "proposed", + "to": "deliberating" + }, + { + "name": "openVoting", + "from": "deliberating", + "to": "voting", + "chairOnly": true, + "guards": [ + "quorum_met" + ] + }, + { + "name": "decide", + "from": "voting", + "to": "decided" + }, + { + "name": "enact", + "from": "decided", + "to": "enacted" + }, + { + "name": "archive", + "from": "enacted", + "to": "archived" + } + ] + }, + "votingRule": { + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "tieBreakRule": "rejected" + }, + "quorumRequired": true, + "quorumRule": "50%+1 of members present or represented", + "allowDecideWithoutVote": false, + "checklist": [] + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-template" + }, + "slug": "association-board", + "name": "Association Board", + "description": "Decision process for an association board (bestuur).", + "context": "association", + "builtIn": true, + "initialState": "draft", + "stateMachine": { + "states": [ + { + "name": "draft" + }, + { + "name": "proposed" + }, + { + "name": "deliberating" + }, + { + "name": "voting" + }, + { + "name": "decided" + }, + { + "name": "enacted" + }, + { + "name": "archived" + } + ], + "transitions": [ + { + "name": "propose", + "from": "draft", + "to": "proposed" + }, + { + "name": "deliberate", + "from": "proposed", + "to": "deliberating" + }, + { + "name": "openVoting", + "from": "deliberating", + "to": "voting", + "chairOnly": true, + "guards": [ + "quorum_met" + ] + }, + { + "name": "decide", + "from": "voting", + "to": "decided" + }, + { + "name": "enact", + "from": "decided", + "to": "enacted" + }, + { + "name": "archive", + "from": "enacted", + "to": "archived" + } + ] + }, + "votingRule": { + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "tieBreakRule": "chair-decides" + }, + "quorumRequired": true, + "quorumRule": "Majority of board members present", + "allowDecideWithoutVote": false, + "checklist": [] + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-template" + }, + "slug": "decharge-bestuur", + "name": "Decharge bestuur", + "description": "Decharge van het bestuur over het afgelopen boekjaar door de algemene ledenvergadering.", + "context": "association", + "decisionType": "resolution", + "templateCategory": "discharge", + "builtIn": true, + "proposedText": "De vergadering verleent het bestuur decharge voor het gevoerde beleid en beheer over het boekjaar {boekjaar}, gehoord de verklaring van de kascommissie.", + "regulationSource": "BW 2:48/2:49", + "votingRule": { + "voteThreshold": "simple-majority" + }, + "checklist": [] + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-template" + }, + "slug": "dotatie-reservefonds", + "name": "Dotatie reservefonds", + "description": "Besluit tot dotatie aan het reservefonds voor groot onderhoud.", + "context": "association", + "decisionType": "resolution", + "templateCategory": "reserve-fund-contribution", + "builtIn": true, + "proposedText": "De vergadering besluit over het boekjaar {boekjaar} een bedrag te doteren aan het reservefonds ten behoeve van toekomstig groot onderhoud, conform de MJOP-grondslag.", + "regulationSource": "Woningwet reservefonds (BW 5:126)", + "votingRule": { + "voteThreshold": "simple-majority" + }, + "checklist": [] + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-template" + }, + "slug": "machtiging-boven-drempel", + "name": "Machtiging bestuur onderhoud boven drempel", + "description": "Machtiging aan het bestuur voor onderhoudsuitgaven boven de in het reglement bepaalde drempel.", + "context": "association", + "decisionType": "resolution", + "templateCategory": "authorisation-above-threshold", + "builtIn": true, + "proposedText": "De vergadering machtigt het bestuur tot het aangaan van de onderhoudsverplichting {omschrijving} voor een bedrag van {bedrag}, welk bedrag de reglementaire drempel overschrijdt.", + "regulationSource": "MR 2017 art. 56 lid 5", + "votingRule": { + "voteThreshold": "qualified-majority-two-thirds" + }, + "quorumRule": "2/3 (MR 2017 art. 56 lid 5)", + "checklist": [] + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-template" + }, + "slug": "vaststelling-jaarrekening", + "name": "Vaststelling jaarrekening", + "description": "Vaststelling van de jaarrekening (exploitatie- en balansoverzicht) van het afgelopen boekjaar.", + "context": "association", + "decisionType": "resolution", + "templateCategory": "annual-accounts", + "builtIn": true, + "proposedText": "De vergadering stelt de jaarrekening over het boekjaar {boekjaar} vast conform het door het bestuur aangeboden exploitatie- en balansoverzicht.", + "regulationSource": "MR 2017 art. 14/15", + "votingRule": { + "voteThreshold": "simple-majority" + }, + "checklist": [] + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-template" + }, + "slug": "vaststelling-mjop", + "name": "Vaststelling/actualisatie MJOP", + "description": "Vaststelling of actualisatie van het meerjarenonderhoudsplan (MJOP).", + "context": "association", + "decisionType": "resolution", + "templateCategory": "mjop-adoption", + "builtIn": true, + "proposedText": "De vergadering stelt het meerjarenonderhoudsplan (MJOP) {periode} vast, respectievelijk actualiseert het geldende MJOP conform het aangeboden concept.", + "regulationSource": "MR 2017 art. 14 (MJOP-grondslag)", + "votingRule": { + "voteThreshold": "simple-majority" + }, + "checklist": [] + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-template" + }, + "slug": "wijziging-huishoudelijk-reglement", + "name": "Wijziging huishoudelijk reglement", + "description": "Wijziging van het huishoudelijk reglement van de vereniging van eigenaars.", + "context": "association", + "decisionType": "resolution", + "templateCategory": "amendment-internal-regulations", + "builtIn": true, + "proposedText": "De vergadering besluit het huishoudelijk reglement te wijzigen conform het aangeboden voorstel {omschrijving}.", + "regulationSource": "MR 2017 art. 60", + "votingRule": { + "voteThreshold": "qualified-majority-two-thirds" + }, + "checklist": [] + } + ], + "geheimhouding-grond": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "geheimhouding-grond" + }, + "slug": "grond-statutair", + "name": "Statutaire vertrouwelijkheid (niet-overheid)", + "citation": "statuten/reglement", + "legacyCitation": null, + "category": "other", + "requiresRatification": true, + "description": "Vertrouwelijkheidsgrond voor niet-overheidsgremia (vereniging, RvC, coöperatie) op basis van statuten of huishoudelijk reglement. Illustreert dat het bekrachtigingsvereiste een eigenschap van de configureerbare grond is, niet van de wet.", + "builtIn": true, + "active": true + } + ], + "goal": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "goal" + }, + "slug": "goal-vng-digitale-dienstverlening-2026", + "title": "Digitale dienstverlening leden", + "description": "Alle VNG-leden kunnen digitaal diensten afnemen bij de vereniging.", + "horizon": "annual", + "body": "ledenraad-vng", + "startDate": "2026-01-01", + "deadline": "2026-12-31", + "status": "draft" + } + ], + "governance-body": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "ledenraad-vng", + "name": "Ledenraad VNG", + "bodyType": "association", + "domain": "association", + "votingDefault": "for-against-abstain", + "termStart": "2024-01-01T00:00:00Z", + "termEnd": "2025-12-31T00:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "vve-parkstaete", + "name": "VvE Parkstaete", + "bodyType": "association", + "domain": "association", + "workflowTemplate": "association", + "votingDefault": "for-against-abstain" + } + ], + "governing-document": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governing-document" + }, + "slug": "splitsingsakte-vve-parkstaete", + "type": "deed-of-division", + "citationTitle": "Splitsingsakte VvE Parkstaete", + "description": "Splitsingsakte (BW 5:111), constitutief bij notariële akte; geen verband met een besluit.", + "governingBody": "vve-parkstaete", + "isPublic": false, + "status": "in-force" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governing-document" + }, + "slug": "statuten-vng", + "type": "articles-of-association", + "citationTitle": "Statuten Vereniging van Nederlandse Gemeenten", + "description": "Statuten van de vereniging (BW 2:27), constitutief bij notariële akte en gewijzigd bij besluit tot statutenwijziging van de ledenraad.", + "governingBody": "ledenraad-vng", + "isPublic": true, + "status": "in-force" + } + ], + "governing-document-versie": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governing-document-versie" + }, + "slug": "splitsingsakte-parkstaete-v1", + "document": "splitsingsakte-vve-parkstaete", + "versionNumber": 1, + "effectiveDate": "2005-06-01", + "notes": "Constitutieve splitsingsakte bij notariële akte; geen verband met een besluit.", + "deedDate": "2005-05-20", + "notary": "mr. B. Jansen", + "status": "in-effect" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governing-document-versie" + }, + "slug": "statuten-vng-v1", + "document": "statuten-vng", + "versionNumber": 1, + "effectiveDate": "1990-05-01", + "notes": "Constitutieve versie bij oprichting van de vereniging; opgericht bij notariële akte, geen verband met een besluit in Decidiq.", + "deedDate": "1990-04-12", + "notary": "mr. C. van Dam", + "status": "replaced" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governing-document-versie" + }, + "slug": "statuten-vng-v2", + "document": "statuten-vng", + "versionNumber": 2, + "determinedBy": "besluit-statutenwijziging-vng-2021", + "effectiveDate": "2022-01-01", + "notes": "Statutenwijziging 2021: aanpassing van de bevoegdheden van de ledenraad (art. 20).", + "deedDate": "2021-12-15", + "notary": "mr. A. de Wit", + "status": "in-effect" + } + ], + "kascommissie-verklaring": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "kascommissie-verklaring" + }, + "slug": "kascommissie-verklaring-2024", + "financialYear": 2024, + "verdict": "qualified", + "notes": "Voorbehoud: onderhoudsfacturen Q3 ontbraken bij controle.", + "governanceBody": "00000000-0000-0000-0000-000000000000" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "kascommissie-verklaring" + }, + "slug": "kascommissie-verklaring-2025", + "financialYear": 2025, + "verdict": "approving", + "notes": "Administratie ordelijk; reservefondsdotatie conform MJOP.", + "agendaItem": "00000000-0000-0000-0000-000000000000", + "governanceBody": "00000000-0000-0000-0000-000000000000" + } + ], + "meeting": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "meeting" + }, + "slug": "ledenvergadering-vng-voorjaar-2025", + "title": "Algemene Ledenvergadering VNG — Voorjaar 2025", + "meetingType": "public hearing", + "scheduledDate": "2025-06-18T13:00:00Z", + "endDate": "2025-06-18T17:00:00Z", + "location": "World Forum Den Haag", + "meetingMode": "in-person", + "lifecycle": "scheduled", + "quorumRequired": 50 + } + ], + "member-consultation": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "member-consultation" + }, + "slug": "ledenraadpleging-alv-contributie", + "question": "Welke contributieverhoging heeft uw voorkeur voor 2027?", + "description": "Peiling onder de leden ter voorbereiding op de ALV; het bestuur legt het definitieve voorstel voor aan de vergadering.", + "responseType": "multi-choice", + "choiceOptions": [ + "Geen verhoging", + "+2%", + "+5%", + "Gedifferentieerd naar leeftijd" + ], + "audienceType": "body-members", + "audienceBody": "00000000-0000-0000-0000-000000000000", + "agendaItem": "rondvraag", + "opensAt": "2026-03-01T09:00:00Z", + "closesAt": "2026-04-01T17:00:00Z", + "anonymousResponses": true, + "lifecycle": "draft" + } + ], + "membership": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "membership" + }, + "slug": "m-marie-vng", + "role": "member", + "label": "Lid ledenraad", + "votingWeight": 1, + "startDate": "2024-01-01T00:00:00Z", + "person": "marie-janssen", + "governanceBody": "ledenraad-vng" + } + ], + "modelreglement-preset": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "modelreglement-preset" + }, + "slug": "modelreglement-1992", + "name": "Modelreglement 1992", + "description": "Modelreglement bij splitsing in appartementsrechten, versie 1992. Categoriemajoriteiten en quora per de artikelen van dit modelreglement. Read-only built-in; dupliceer om af te wijken.", + "builtIn": true, + "categoryRules": [ + { + "decisionCategory": "authorisation-above-threshold", + "voteThreshold": "qualified-majority-three-quarters", + "quorumFraction": "2/3", + "article": "MR 1992 art. 38 lid 5" + }, + { + "decisionCategory": "amendment-internal-regulations", + "voteThreshold": "qualified-majority-two-thirds", + "quorumFraction": null, + "article": "MR 1992 art. 44" + }, + { + "decisionCategory": "other", + "voteThreshold": "simple-majority", + "quorumFraction": null, + "article": "MR 1992 hoofdregel gewone meerderheid" + } + ] + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "modelreglement-preset" + }, + "slug": "modelreglement-2006", + "name": "Modelreglement 2006", + "description": "Modelreglement bij splitsing in appartementsrechten, versie 2006. Categoriemajoriteiten en quora per de artikelen van dit modelreglement. Read-only built-in; dupliceer om af te wijken.", + "builtIn": true, + "categoryRules": [ + { + "decisionCategory": "authorisation-above-threshold", + "voteThreshold": "qualified-majority-two-thirds", + "quorumFraction": "2/3", + "article": "MR 2006 art. 52 lid 5" + }, + { + "decisionCategory": "amendment-internal-regulations", + "voteThreshold": "qualified-majority-two-thirds", + "quorumFraction": null, + "article": "MR 2006 art. 59" + }, + { + "decisionCategory": "other", + "voteThreshold": "simple-majority", + "quorumFraction": null, + "article": "MR 2006 hoofdregel gewone meerderheid" + } + ] + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "modelreglement-preset" + }, + "slug": "modelreglement-2017", + "name": "Modelreglement 2017", + "description": "Modelreglement bij splitsing in appartementsrechten, versie 2017. Categoriemajoriteiten en quora per de artikelen van dit modelreglement. Read-only built-in; dupliceer om af te wijken.", + "builtIn": true, + "categoryRules": [ + { + "decisionCategory": "authorisation-above-threshold", + "voteThreshold": "qualified-majority-two-thirds", + "quorumFraction": "2/3", + "article": "MR 2017 art. 56 lid 5" + }, + { + "decisionCategory": "amendment-internal-regulations", + "voteThreshold": "qualified-majority-two-thirds", + "quorumFraction": null, + "article": "MR 2017 art. 60" + }, + { + "decisionCategory": "other", + "voteThreshold": "simple-majority", + "quorumFraction": null, + "article": "MR 2017 hoofdregel gewone meerderheid" + } + ] + } + ], + "participant": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "participant" + }, + "slug": "ans-rutten", + "displayName": "Ans Rutten", + "role": "observer", + "email": "a.rutten@vng.nl", + "joinedAt": "2024-01-10T00:00:00Z", + "votingWeight": 0 + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "participant" + }, + "slug": "jan-de-vries", + "displayName": "Jan de Vries", + "role": "secretary", + "email": "j.devries@waterschap.nl", + "joinedAt": "2021-01-15T00:00:00Z", + "votingWeight": 1 + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "participant" + }, + "slug": "marie-janssen", + "displayName": "Marie Janssen", + "role": "member", + "party": "D66", + "email": "m.janssen@amsterdam.nl", + "joinedAt": "2022-03-16T00:00:00Z", + "votingWeight": 1 + } + ], + "pc-cyclus": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "pc-cyclus" + }, + "slug": "jaarcyclus-2026-vereniging", + "name": "Jaarcyclus 2026", + "year": 2026, + "governanceBody": "00000000-0000-0000-0000-000000000000", + "template": "association-jaarstukken", + "stepCount": 5, + "completedStepCount": 0, + "overdueStepCount": 0 + } + ], + "person": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "person" + }, + "slug": "jan-de-vries", + "name": "Jan de Vries", + "givenName": "Jan", + "familyName": "de Vries", + "gender": "male", + "email": "j.devries@waterschap.nl", + "biography": "Secretaris / griffier." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "person" + }, + "slug": "marie-janssen", + "name": "Marie Janssen", + "givenName": "Marie", + "familyName": "Janssen", + "gender": "female", + "email": "m.janssen@amsterdam.nl", + "biography": "Raadslid en lid van de VNG-ledenraad." + } + ], + "process-template": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "process-template" + }, + "slug": "association-alv", + "name": "Association ALV", + "description": "Standard decision process for a Dutch association general meeting (ALV), BW Book 2.", + "context": "association", + "builtIn": true, + "initialState": "draft", + "stateMachine": { + "states": [ + { + "name": "draft" + }, + { + "name": "proposed" + }, + { + "name": "deliberating" + }, + { + "name": "voting" + }, + { + "name": "decided" + }, + { + "name": "enacted" + }, + { + "name": "archived" + } + ], + "transitions": [ + { + "name": "propose", + "from": "draft", + "to": "proposed" + }, + { + "name": "deliberate", + "from": "proposed", + "to": "deliberating" + }, + { + "name": "openVoting", + "from": "deliberating", + "to": "voting", + "chairOnly": true, + "guards": [ + "quorum_met" + ] + }, + { + "name": "decide", + "from": "voting", + "to": "decided" + }, + { + "name": "enact", + "from": "decided", + "to": "enacted" + }, + { + "name": "archive", + "from": "enacted", + "to": "archived" + } + ] + }, + "votingRule": { + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "tieBreakRule": "rejected" + }, + "quorumRequired": true, + "quorumRule": "50%+1 of members present or represented", + "allowDecideWithoutVote": false + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "process-template" + }, + "slug": "association-alv-statutaire-volmacht", + "name": "ALV met statutaire volmachtgrens", + "description": "Duplicated Association ALV template (builtIn:false) demonstrating the per-body override: statuten cap one proxy per holder and require a signed machtiging. Cloned from the association-alv built-in; the built-in itself ships both new keys unset (global fallback).", + "context": "association", + "builtIn": false, + "initialState": "draft", + "stateMachine": { + "states": [ + { + "name": "draft" + }, + { + "name": "proposed" + }, + { + "name": "deliberating" + }, + { + "name": "voting" + }, + { + "name": "decided" + }, + { + "name": "enacted" + }, + { + "name": "archived" + } + ], + "transitions": [ + { + "name": "propose", + "from": "draft", + "to": "proposed" + }, + { + "name": "deliberate", + "from": "proposed", + "to": "deliberating" + }, + { + "name": "openVoting", + "from": "deliberating", + "to": "voting", + "chairOnly": true, + "guards": [ + "quorum_met" + ] + }, + { + "name": "decide", + "from": "voting", + "to": "decided" + }, + { + "name": "enact", + "from": "decided", + "to": "enacted" + }, + { + "name": "archive", + "from": "enacted", + "to": "archived" + } + ] + }, + "votingRule": { + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "tieBreakRule": "rejected", + "maxProxiesPerHolder": 1, + "requireSignedProxy": true + }, + "quorumRequired": true, + "quorumRule": "50%+1 of members present or represented", + "allowDecideWithoutVote": false + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "process-template" + }, + "slug": "association-board", + "name": "Association Board", + "description": "Decision process for an association board (bestuur).", + "context": "association", + "builtIn": true, + "initialState": "draft", + "stateMachine": { + "states": [ + { + "name": "draft" + }, + { + "name": "proposed" + }, + { + "name": "deliberating" + }, + { + "name": "voting" + }, + { + "name": "decided" + }, + { + "name": "enacted" + }, + { + "name": "archived" + } + ], + "transitions": [ + { + "name": "propose", + "from": "draft", + "to": "proposed" + }, + { + "name": "deliberate", + "from": "proposed", + "to": "deliberating" + }, + { + "name": "openVoting", + "from": "deliberating", + "to": "voting", + "chairOnly": true, + "guards": [ + "quorum_met" + ] + }, + { + "name": "decide", + "from": "voting", + "to": "decided" + }, + { + "name": "enact", + "from": "decided", + "to": "enacted" + }, + { + "name": "archive", + "from": "enacted", + "to": "archived" + } + ] + }, + "votingRule": { + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "tieBreakRule": "chair-decides" + }, + "quorumRequired": true, + "quorumRule": "Majority of board members present", + "allowDecideWithoutVote": false + } + ], + "proxy-authorization": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "proxy-authorization" + }, + "slug": "machtiging-alv-jansen-ongetekend", + "grantor": "00000000-0000-0000-0000-000000000000", + "holder": "marie-janssen", + "meeting": "ledenvergadering-vng-voorjaar-2025", + "signatureStatus": "unsigned" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "proxy-authorization" + }, + "slug": "machtiging-jansen-alv-2026", + "grantor": "marie-janssen", + "holder": "jan-de-vries", + "meeting": "ledenvergadering-vng-voorjaar-2025", + "signatureStatus": "signed", + "signedAt": "2026-04-10T08:30:00Z", + "signingReference": "docudesk:sign:seed-jansen-alv-2026", + "proxyStatus": "active" + } + ], + "regeling": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "regeling" + }, + "slug": "huishoudelijk-reglement-vng", + "type": "regulations", + "citationTitle": "Huishoudelijk reglement ledenraad VNG", + "officialTitle": "Huishoudelijk reglement van de ledenraad van de Vereniging van Nederlandse Gemeenten", + "statutoryBasis": [ + "Statuten VNG art. 12" + ], + "determiningBody": "ledenraad-vng", + "status": "adopted" + } + ], + "regeling-versie": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "regeling-versie" + }, + "slug": "hr-vng-v1", + "regulation": "huishoudelijk-reglement-vng", + "versionNumber": 1, + "determinedBy": "00000000-0000-0000-0000-000000000000", + "effectiveDate": "2026-09-01", + "notes": "Concept eerste huishoudelijk reglement; treedt in werking na vaststelling door de ledenraad.", + "status": "draft" + } + ], + "vve-configuration": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "vve-configuration" + }, + "slug": "vve-parkstaete-configuratie", + "governanceBody": "vve-parkstaete", + "modelRegulation": "modelreglement-2017", + "modelReglementVersion": "2017", + "fractionDenominator": 10000, + "deedOfDivisionDocument": "splitsingsakte-vve-parkstaete", + "majorityOverrides": [ + { + "decisionCategory": "amendment-internal-regulations", + "templateCategory": "amendment-internal-regulations", + "voteThreshold": "qualified-majority-three-quarters", + "quorumFraction": null, + "deedArticle": "splitsingsakte VvE Parkstaete art. 62" + } + ] + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "vve-configuration" + }, + "slug": "vve-zeewaarts-configuratie", + "governanceBody": "00000000-0000-0000-0000-000000000000", + "modelRegulation": "modelreglement-2017", + "fractionDenominator": 10000, + "deedOfDivisionDocument": "00000000-0000-0000-0000-000000000000", + "majorityOverrides": [ + { + "decisionCategory": "amendment-internal-regulations", + "voteThreshold": "qualified-majority-three-quarters", + "quorumFraction": null, + "deedArticle": "splitsingsakte 2019 art. 62" + } + ] + } + ], + "vve-decision-template": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "vve-decision-template" + }, + "slug": "decharge-bestuur", + "name": "Decharge bestuur", + "description": "Decharge van het bestuur over het afgelopen boekjaar door de algemene ledenvergadering.", + "decisionCategory": "discharge", + "proposedText": "De vergadering verleent het bestuur decharge voor het gevoerde beleid en beheer over het boekjaar {boekjaar}, gehoord de verklaring van de kascommissie.", + "builtIn": true, + "defaultVoteThreshold": "simple-majority", + "defaultQuorumFraction": null, + "regulationSource": "BW 2:48/2:49" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "vve-decision-template" + }, + "slug": "dotatie-reservefonds", + "name": "Dotatie reservefonds", + "description": "Besluit tot dotatie aan het reservefonds voor groot onderhoud.", + "decisionCategory": "reserve-fund-contribution", + "proposedText": "De vergadering besluit over het boekjaar {boekjaar} een bedrag te doteren aan het reservefonds ten behoeve van toekomstig groot onderhoud, conform de MJOP-grondslag.", + "builtIn": true, + "defaultVoteThreshold": "simple-majority", + "defaultQuorumFraction": null, + "regulationSource": "Woningwet reservefonds (BW 5:126)" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "vve-decision-template" + }, + "slug": "machtiging-boven-drempel", + "name": "Machtiging bestuur onderhoud boven drempel", + "description": "Machtiging aan het bestuur voor onderhoudsuitgaven boven de in het reglement bepaalde drempel.", + "decisionCategory": "authorisation-above-threshold", + "proposedText": "De vergadering machtigt het bestuur tot het aangaan van de onderhoudsverplichting {omschrijving} voor een bedrag van {bedrag}, welk bedrag de reglementaire drempel overschrijdt.", + "builtIn": true, + "defaultVoteThreshold": "qualified-majority-two-thirds", + "defaultQuorumFraction": "2/3", + "regulationSource": "MR 2017 art. 56 lid 5" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "vve-decision-template" + }, + "slug": "vaststelling-jaarrekening", + "name": "Vaststelling jaarrekening", + "description": "Vaststelling van de jaarrekening (exploitatie- en balansoverzicht) van het afgelopen boekjaar.", + "decisionCategory": "annual-accounts", + "proposedText": "De vergadering stelt de jaarrekening over het boekjaar {boekjaar} vast conform het door het bestuur aangeboden exploitatie- en balansoverzicht.", + "builtIn": true, + "defaultVoteThreshold": "simple-majority", + "defaultQuorumFraction": null, + "regulationSource": "MR 2017 art. 14/15" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "vve-decision-template" + }, + "slug": "vaststelling-mjop", + "name": "Vaststelling/actualisatie MJOP", + "description": "Vaststelling of actualisatie van het meerjarenonderhoudsplan (MJOP).", + "decisionCategory": "mjop-adoption", + "proposedText": "De vergadering stelt het meerjarenonderhoudsplan (MJOP) {periode} vast, respectievelijk actualiseert het geldende MJOP conform het aangeboden concept.", + "builtIn": true, + "defaultVoteThreshold": "simple-majority", + "defaultQuorumFraction": null, + "regulationSource": "MR 2017 art. 14 (MJOP-grondslag)" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "vve-decision-template" + }, + "slug": "wijziging-huishoudelijk-reglement", + "name": "Wijziging huishoudelijk reglement", + "description": "Wijziging van het huishoudelijk reglement van de vereniging van eigenaars.", + "decisionCategory": "amendment-internal-regulations", + "proposedText": "De vergadering besluit het huishoudelijk reglement te wijzigen conform het aangeboden voorstel {omschrijving}.", + "builtIn": true, + "defaultVoteThreshold": "qualified-majority-two-thirds", + "defaultQuorumFraction": null, + "regulationSource": "MR 2017 art. 60" + } + ] + } + } + }, + "paths": {}, + "components": {} +} diff --git a/lib/Settings/profiles/corporate.json b/lib/Settings/profiles/corporate.json new file mode 100644 index 000000000..58ea2413e --- /dev/null +++ b/lib/Settings/profiles/corporate.json @@ -0,0 +1,2151 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Decidiq example set: Company board", + "version": "1.0.0", + "description": "A supervisory board, an executive board and a management team. Terms, conflicts of interest and evaluations." + }, + "x-openregister": { + "type": "profile", + "app": "decidiq", + "profile": { + "id": "corporate", + "label": "Company board", + "description": "A supervisory board, an executive board and a management team. Terms, conflicts of interest and evaluations.", + "order": 3, + "objectCount": 91 + }, + "description": "An example set an operator picks in the first-time setup wizard (ADR-042). NEVER imported on install: the register.d fragments declare schemas only, so a bare install has zero objects. Every object carries @self.configuration/register/schema so the import resolves the live decidiq register WITHOUT this descriptor declaring components.registers. That is deliberate and load-bearing: ImportHandler::importRegister() calls setApplication($appId) unconditionally on an existing register, so a descriptor that declared the register would re-point the decidiq register at this profile config id and hydrate over its authorization baseline. Verified on a live instance: importing this shape left application=decidiq, version and authorization byte-identical. Import is idempotent by slug, so loading a profile twice adds nothing. Descriptors live in this SUBDIRECTORY on purpose: RegisterDescriptorService scans lib/Settings/*.json non-recursively and matches descriptors by declared register slug, so four profile files in lib/Settings would collide with each other and with decidesk_register.json.", + "seedData": { + "description": "Example objects for the company board set.", + "objects": { + "action-item": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "action-item" + }, + "slug": "actie-duurzaamheid-offerteverzoek", + "title": "Offerteverzoek zonnepanelen gemeentelijke gebouwen uitzetten", + "description": "Inkoopteam vraagt offertes op bij minimaal 3 leveranciers conform gemeentelijk aanbestedingsbeleid.", + "assignee": "Inkoopcoördinator", + "dueDate": "2025-05-15T00:00:00Z", + "taskStatus": "completed", + "completedAt": "2025-05-10T16:00:00Z" + } + ], + "agenda-item": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "pub-quiz-2026-09-opening", + "title": "Welcome and rules", + "type": "c7d10000-0000-4000-a000-000000000022", + "itemType": "informational", + "orderNumber": 1, + "estimatedDuration": 5, + "meeting": "c7d10000-0000-4000-a000-000000000041", + "description": "The quizmaster opens the evening." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "pub-quiz-2026-09-q1", + "title": "Which team ships more Friday deploys?", + "type": "c7d10000-0000-4000-a000-000000000021", + "itemType": "decision", + "orderNumber": 2, + "estimatedDuration": 10, + "meeting": "c7d10000-0000-4000-a000-000000000041", + "description": "Votable quiz question. The teams present are the Management team and the Development team, resolved through the Pub quiz body's two direct compositions — nobody was added to the Pub quiz by hand.", + "id": "c7d10000-0000-4000-a000-000000000042", + "uuid": "c7d10000-0000-4000-a000-000000000042" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "pub-quiz-2026-09-q2", + "title": "Should the next quiz be held off-site?", + "type": "c7d10000-0000-4000-a000-000000000021", + "itemType": "decision", + "orderNumber": 3, + "estimatedDuration": 10, + "meeting": "c7d10000-0000-4000-a000-000000000041", + "description": "Votable quiz question.", + "id": "c7d10000-0000-4000-a000-000000000043", + "uuid": "c7d10000-0000-4000-a000-000000000043" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "pub-quiz-2026-09-q3", + "title": "Is a tie broken by the quizmaster?", + "type": "c7d10000-0000-4000-a000-000000000021", + "itemType": "decision", + "orderNumber": 4, + "estimatedDuration": 10, + "meeting": "c7d10000-0000-4000-a000-000000000041", + "description": "Votable quiz question.", + "id": "c7d10000-0000-4000-a000-000000000044", + "uuid": "c7d10000-0000-4000-a000-000000000044" + } + ], + "agenda-item-type": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item-type" + }, + "slug": "agenda-item-type-quiz-question", + "name": "Quiz question", + "owningBody": "c7d10000-0000-4000-a000-000000000003", + "votable": true, + "order": 1, + "isDraft": false, + "active": true, + "initialLifecycle": "open", + "lifecycleStates": [ + "open", + "voting", + "scored" + ], + "description": "A question the assembled teams vote on. Votable, so it carries a voting round; owned by the Pub quiz body.", + "fields": [ + { + "key": "correctAnswer", + "label": "Correct answer", + "fieldType": "string", + "required": false + }, + { + "key": "points", + "label": "Points", + "fieldType": "number", + "required": false + } + ], + "id": "c7d10000-0000-4000-a000-000000000021", + "uuid": "c7d10000-0000-4000-a000-000000000021" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item-type" + }, + "slug": "agenda-item-type-quiz-round-opening", + "name": "Round opening", + "owningBody": "c7d10000-0000-4000-a000-000000000003", + "votable": false, + "order": 0, + "isDraft": false, + "active": true, + "initialLifecycle": "open", + "description": "Non-votable housekeeping item — proves a meeting type admits more than one item kind.", + "id": "c7d10000-0000-4000-a000-000000000022", + "uuid": "c7d10000-0000-4000-a000-000000000022" + } + ], + "board-evaluation": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "board-evaluation" + }, + "slug": "evaluatie-acme-rvc-2026", + "cycleLabel": "2026", + "lifecycle": "open", + "openedAt": "2026-06-01T09:00:00Z", + "invitedMemberCount": 5, + "respondedCount": 2, + "minRespondentThreshold": 3, + "invitedParticipantIds": [ + "acme-lid-1", + "acme-lid-2", + "acme-lid-3", + "acme-lid-4", + "acme-lid-5" + ], + "respondedParticipantIds": [ + "acme-lid-1", + "acme-lid-2" + ], + "chairUserId": "acme.chair", + "secretaryUserId": "acme.secretary", + "governanceBody": "raad-van-commissarissen-acme-bv", + "template": "template-bestuurlijke-effectiviteit" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "board-evaluation" + }, + "slug": "evaluatie-rvc-waterschap-amstel-2025", + "cycleLabel": "2025", + "lifecycle": "closed", + "openedAt": "2025-11-01T09:00:00Z", + "closedAt": "2025-12-20T17:00:00Z", + "invitedMemberCount": 3, + "respondedCount": 2, + "minRespondentThreshold": 3, + "invitedParticipantIds": [ + "jan-de-vries", + "femke-halsema", + "marie-janssen" + ], + "respondedParticipantIds": [ + "jan-de-vries", + "femke-halsema" + ], + "chairUserId": "femke.halsema", + "secretaryUserId": "jan.devries", + "scoreSummary": "{\"overallScore\":3.6,\"respondentCount\":2,\"invitedMemberCount\":3,\"minRespondentThreshold\":3,\"thresholdMet\":false,\"suppressed\":true,\"dimensionScores\":null,\"themes\":null,\"computedAt\":\"2025-12-20T17:05:00Z\"}", + "governanceBody": "rvc-waterschap-amstel", + "template": "template-bestuurlijke-effectiviteit" + } + ], + "conflict-of-interest": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "conflict-of-interest" + }, + "slug": "coi-ben-r002", + "boardMember": "ben-okonkwo-rvc-acme", + "agendaItem": "r-2025-002-appointment-cfo", + "declarationType": "personal-relationship", + "description": "Familierelatie met kandidaat-CFO.", + "severity": "material", + "actionTaken": "recused-from-vote", + "declarationTimestamp": "2025-03-12T16:50:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "conflict-of-interest" + }, + "slug": "coi-hannah-r002", + "boardMember": "hannah-stein-rvc-acme", + "agendaItem": "r-2025-002-appointment-cfo", + "declarationType": "none", + "actionTaken": "no-action-needed", + "declarationTimestamp": "2025-03-12T16:48:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "conflict-of-interest" + }, + "slug": "coi-klaas-strategy", + "boardMember": "klaas-mulder-rvc-acme", + "declarationType": "prior-involvement", + "description": "Voormalig CEO van strategieadviseur die de strategiedag faciliteert.", + "severity": "non-material", + "actionTaken": "disclosed-and-participated", + "declarationTimestamp": "2025-09-18T09:05:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "conflict-of-interest" + }, + "slug": "coi-mark-r003", + "boardMember": "mark-van-den-berg-rvb-acme", + "agendaItem": "r-2025-003-financial-acquisition", + "declarationType": "financial-interest", + "description": "Indirect aandelenbelang in target via family-trust (<1%).", + "severity": "non-material", + "actionTaken": "disclosed-and-participated", + "declarationTimestamp": "2025-04-22T17:45:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "conflict-of-interest" + }, + "slug": "coi-petra-r005", + "boardMember": "petra-jansen-rvc-acme", + "agendaItem": "r-2025-005-policy-procurement", + "declarationType": "competing-business", + "description": "Bestuurslid bij Stichting Procurement Excellence.", + "severity": "non-material", + "actionTaken": "disclosed-and-participated", + "declarationTimestamp": "2025-03-12T17:10:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "conflict-of-interest" + }, + "slug": "coi-sandra-r004", + "boardMember": "sandra-yilmaz-rvb-acme", + "declarationType": "prior-involvement", + "description": "Eerder consultancy-werk voor ESG-adviseur die de strategie heeft opgesteld.", + "severity": "non-material", + "actionTaken": "no-action-needed", + "declarationTimestamp": "2025-04-22T17:30:00Z" + } + ], + "decision": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "benoeming-lid-rvc-acme-van-duin", + "decisionType": "appointment", + "title": "Benoeming lid Raad van Commissarissen ACME B.V.", + "text": "Voordracht van mevrouw J. van Duin (externe werving) als lid van de Raad van Commissarissen, conform profielschets — herbenoeming van de huidige commissaris was niet mogelijk op grond van het rooster van aftreden.", + "lifecycle": "enacted", + "outcome": "adopted", + "decisionDate": "2026-04-10T19:00:00Z", + "targetBody": "raad-van-commissarissen-acme-bv", + "targetPosts": [], + "targetRole": "member", + "candidates": [ + { + "externalName": "Mw. J. van Duin", + "notes": "Externe werving; nog geen Person-registratie — wordt na benoeming aangemaakt." + } + ], + "nominatingParty": { + "type": "body", + "name": "Raad van Commissarissen (coöptatie-voordracht)" + }, + "appointedMemberships": [], + "isPublished": "internal" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "besluit-investering-acme", + "decisionType": "management-point", + "title": "Investeringsbesluit Datacenteruitbreiding ACME B.V.", + "text": "Het MT besluit tot investering in uitbreiding van het datacentercapaciteit met €2,4M conform de goedgekeurde businesscase.", + "decisionDate": "2026-05-01T10:00:00Z", + "outcome": "adopted", + "isPublished": "confidential", + "lifecycle": "decided", + "route": [ + "stage-investering-acme-1-prep", + "stage-investering-acme-2-dec", + "stage-investering-acme-3-rat" + ] + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "contract-schoonmaak-2026", + "decisionType": "contract", + "title": "Gunning schoonmaakcontract 2026", + "text": "Het MT gunt het schoonmaakcontract aan Leverancier X.", + "legalBasis": "Aanbestedingswet 2012", + "lifecycle": "decided", + "outcome": "adopted", + "decisionDate": "2026-01-22T14:00:00Z", + "isPublished": "confidential" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "mt-go-nogo-zonnepark", + "decisionType": "management-point", + "title": "Go/No-go zonnepark fase 2", + "text": "Het MT besluit fase 2 van het zonnepark vrij te geven voor realisatie, onder voorbehoud van de definitieve netaansluiting.", + "lifecycle": "decided", + "outcome": "adopted", + "decisionDate": "2026-03-03T09:45:00Z", + "isPublished": "internal" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "pub-quiz-2026-09-decision-q1", + "id": "c7d10000-0000-4000-a000-000000000071", + "uuid": "c7d10000-0000-4000-a000-000000000071", + "title": "Which team ships more Friday deploys?", + "text": "Resolution recorded for quiz question 1 of the September 2026 pub quiz.", + "decisionType": "motion", + "type": "c7d10000-0000-4000-a000-000000000051", + "agendaItem": "c7d10000-0000-4000-a000-000000000042", + "lifecycle": "voting", + "votingOrder": 1, + "voteType": "named", + "voteThreshold": "simple-majority" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "pub-quiz-2026-09-decision-q2", + "id": "c7d10000-0000-4000-a000-000000000072", + "uuid": "c7d10000-0000-4000-a000-000000000072", + "title": "Should the next quiz be held off-site?", + "text": "Resolution recorded for quiz question 2 of the September 2026 pub quiz.", + "decisionType": "motion", + "type": "c7d10000-0000-4000-a000-000000000051", + "agendaItem": "c7d10000-0000-4000-a000-000000000043", + "lifecycle": "voting", + "votingOrder": 2, + "voteType": "named", + "voteThreshold": "simple-majority" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "pub-quiz-2026-09-decision-q3", + "id": "c7d10000-0000-4000-a000-000000000073", + "uuid": "c7d10000-0000-4000-a000-000000000073", + "title": "Is a tie broken by the quizmaster?", + "text": "Resolution recorded for quiz question 3 of the September 2026 pub quiz.", + "decisionType": "motion", + "type": "c7d10000-0000-4000-a000-000000000051", + "agendaItem": "c7d10000-0000-4000-a000-000000000044", + "lifecycle": "voting", + "votingOrder": 3, + "voteType": "named", + "voteThreshold": "simple-majority" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "r-2025-001-goedkeuring-jaarrekening", + "decisionType": "resolution", + "title": "Goedkeuring jaarrekening 2024", + "text": "De RvC verleent goedkeuring aan de jaarrekening 2024.", + "resolutionNumber": "R-2025-001", + "voteType": "named", + "voteThreshold": "simple-majority", + "legalBasis": "art. 2:101 BW", + "lifecycle": "enacted", + "outcome": "adopted", + "decisionDate": "2025-05-14T10:30:00Z", + "isPublished": "internal" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "r-2025-002-benoeming-cfo", + "decisionType": "resolution", + "title": "Benoeming CFO", + "text": "De RvC benoemt met ingang van 1 juli 2025 mevrouw A. Jansen tot Chief Financial Officer van de vennootschap.", + "resolutionNumber": "R-2025-002", + "voteType": "anonymous", + "voteThreshold": "simple-majority", + "lifecycle": "enacted", + "outcome": "adopted", + "decisionDate": "2025-05-14T11:15:00Z", + "isPublished": "confidential" + } + ], + "decision-stage": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-stage" + }, + "slug": "pub-quiz-2026-09-stage-q1", + "id": "c7d10000-0000-4000-a000-000000000081", + "uuid": "c7d10000-0000-4000-a000-000000000081", + "sequence": 1, + "mandatory": true, + "stageType": "decisive", + "status": "active", + "method": "vote", + "decisionMakerType": "body", + "label": "Vote on question 1", + "decision": "c7d10000-0000-4000-a000-000000000071", + "assignedBody": "c7d10000-0000-4000-a000-000000000003", + "votingRound": "c7d10000-0000-4000-a000-000000000061" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-stage" + }, + "slug": "pub-quiz-2026-09-stage-q2", + "id": "c7d10000-0000-4000-a000-000000000082", + "uuid": "c7d10000-0000-4000-a000-000000000082", + "sequence": 1, + "mandatory": true, + "stageType": "decisive", + "status": "active", + "method": "vote", + "decisionMakerType": "body", + "label": "Vote on question 2", + "decision": "c7d10000-0000-4000-a000-000000000072", + "assignedBody": "c7d10000-0000-4000-a000-000000000003", + "votingRound": "c7d10000-0000-4000-a000-000000000062" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-stage" + }, + "slug": "pub-quiz-2026-09-stage-q3", + "id": "c7d10000-0000-4000-a000-000000000083", + "uuid": "c7d10000-0000-4000-a000-000000000083", + "sequence": 1, + "mandatory": true, + "stageType": "decisive", + "status": "active", + "method": "vote", + "decisionMakerType": "body", + "label": "Vote on question 3", + "decision": "c7d10000-0000-4000-a000-000000000073", + "assignedBody": "c7d10000-0000-4000-a000-000000000003", + "votingRound": "c7d10000-0000-4000-a000-000000000063" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-stage" + }, + "slug": "stage-investering-acme-1-prep", + "sequence": 1, + "stageType": "preparatory", + "status": "decided", + "outcome": "adopted", + "decidedAt": "2026-04-05T11:00:00Z", + "method": "chair-register", + "decisionMakerType": "body", + "label": "MT-voorbereiding investering", + "note": "Businesscase goedgekeurd door MT-voorzitter.", + "decision": "besluit-investering-acme", + "assignedBody": "managementteam-acme-bv", + "registeredBy": "mark-van-den-berg" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-stage" + }, + "slug": "stage-investering-acme-2-dec", + "sequence": 2, + "stageType": "decisive", + "status": "decided", + "outcome": "adopted", + "decidedAt": "2026-04-18T15:30:00Z", + "method": "vote", + "decisionMakerType": "body", + "label": "Besluit Raad van Bestuur", + "note": "Investeringsbesluit aangenomen — geheime stemming, unanime uitkomst.", + "decision": "besluit-investering-acme", + "assignedBody": "raad-van-bestuur-acme-bv", + "votingRound": "stemming-investering-acme-rvb-geheim" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-stage" + }, + "slug": "stage-investering-acme-3-rat", + "sequence": 3, + "stageType": "ratifying", + "status": "decided", + "outcome": "adopted", + "decidedAt": "2026-05-01T09:15:00Z", + "method": "signature", + "decisionMakerType": "body", + "label": "Goedkeuring Raad van Commissarissen — eIDAS ondertekening", + "note": "RvC-besluit bekrachtigd via QES-handtekeningen. Notulen ondertekend door voorzitter en secretaris.", + "decision": "besluit-investering-acme", + "assignedBody": "raad-van-commissarissen-acme-bv", + "signedDocument": "notulen-rvc-investering-acme-signed" + } + ], + "decision-template": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-template" + }, + "slug": "corporate-board", + "name": "Corporate Board (BV)", + "description": "Decision process for the management board of a Dutch private limited company (BV).", + "context": "corporate", + "builtIn": true, + "initialState": "draft", + "stateMachine": { + "states": [ + { + "name": "draft" + }, + { + "name": "proposed" + }, + { + "name": "deliberating" + }, + { + "name": "voting" + }, + { + "name": "decided" + }, + { + "name": "enacted" + }, + { + "name": "archived" + } + ], + "transitions": [ + { + "name": "propose", + "from": "draft", + "to": "proposed" + }, + { + "name": "deliberate", + "from": "proposed", + "to": "deliberating" + }, + { + "name": "openVoting", + "from": "deliberating", + "to": "voting", + "chairOnly": true, + "guards": [ + "quorum_met" + ] + }, + { + "name": "decide", + "from": "voting", + "to": "decided" + }, + { + "name": "enact", + "from": "decided", + "to": "enacted" + }, + { + "name": "archive", + "from": "enacted", + "to": "archived" + } + ] + }, + "votingRule": { + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "tieBreakRule": "chair-decides" + }, + "quorumRequired": true, + "quorumRule": "Quorum per the articles of association", + "allowDecideWithoutVote": false, + "checklist": [] + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-template" + }, + "slug": "corporate-board-urgent", + "name": "Corporate Board (urgency-enabled)", + "description": "Corporate management board (RvB) process template with the urgent-decision procedure enabled: urgent resolution decided via an expedited 24h written round, ratified by the Raad van Commissarissen.", + "context": "corporate", + "builtIn": false, + "initialState": "draft", + "stateMachine": { + "states": [ + { + "name": "draft" + }, + { + "name": "proposed" + }, + { + "name": "deliberating" + }, + { + "name": "voting" + }, + { + "name": "decided" + }, + { + "name": "enacted" + }, + { + "name": "archived" + } + ], + "transitions": [ + { + "name": "propose", + "from": "draft", + "to": "proposed" + }, + { + "name": "deliberate", + "from": "proposed", + "to": "deliberating" + }, + { + "name": "openVoting", + "from": "deliberating", + "to": "voting", + "chairOnly": true, + "guards": [ + "quorum_met" + ] + }, + { + "name": "decide", + "from": "voting", + "to": "decided" + }, + { + "name": "enact", + "from": "decided", + "to": "enacted" + }, + { + "name": "archive", + "from": "enacted", + "to": "archived" + } + ] + }, + "votingRule": { + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "tieBreakRule": "chair-decides" + }, + "quorumRequired": true, + "quorumRule": "Quorum per the articles of association", + "allowDecideWithoutVote": false, + "urgencyPolicy": { + "allowedTriggerRoles": [ + "chair", + "secretary" + ], + "minimumNoticeFloorHours": 12, + "responseDeadlineHours": { + "min": 4, + "max": 72 + }, + "ratificationRequired": true, + "ratifyingBody": "raad-van-commissarissen-acme-bv" + }, + "checklist": [] + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-template" + }, + "slug": "decision-type-quiz-answer", + "id": "c7d10000-0000-4000-a000-000000000051", + "uuid": "c7d10000-0000-4000-a000-000000000051", + "name": "Quiz answer", + "description": "A quiz question put to the assembled teams. Demonstrates REQ-CTM-003/004: the decision references this TYPE rather than copying it, and the type names the gremium competent to take it.", + "decisionType": "motion", + "context": "operations", + "builtIn": false, + "competentBody": "c7d10000-0000-4000-a000-000000000003", + "competentPositionTypes": [ + "c7d10000-0000-4000-a000-000000000011" + ], + "quorumRequired": true, + "quorumRule": "majority", + "allowDecideWithoutVote": false, + "initialState": "proposed" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-template" + }, + "slug": "operational-team", + "name": "Operational Team", + "description": "Lightweight decision process for an operational/management team; formal voting rounds are optional.", + "context": "operations", + "builtIn": true, + "initialState": "draft", + "stateMachine": { + "states": [ + { + "name": "draft" + }, + { + "name": "proposed" + }, + { + "name": "deliberating" + }, + { + "name": "decided" + }, + { + "name": "enacted" + }, + { + "name": "archived" + } + ], + "transitions": [ + { + "name": "propose", + "from": "draft", + "to": "proposed" + }, + { + "name": "deliberate", + "from": "proposed", + "to": "deliberating" + }, + { + "name": "decide", + "from": "deliberating", + "to": "decided" + }, + { + "name": "enact", + "from": "decided", + "to": "enacted" + }, + { + "name": "archive", + "from": "enacted", + "to": "archived" + } + ] + }, + "votingRule": { + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "tieBreakRule": "rejected" + }, + "quorumRequired": false, + "quorumRule": "No formal quorum", + "allowDecideWithoutVote": true, + "checklist": [] + } + ], + "digital-document": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "digital-document" + }, + "slug": "notulen-rvc-investering-acme-signed", + "name": "Ondertekende notulen RvC — Investeringsbesluit Datacenteruitbreiding ACME B.V.", + "documentType": "signed-minutes", + "description": "QES-ondertekende notulen van de RvC-vergadering betreffende het investeringsbesluit datacenteruitbreiding. Ondertekend door voorzitter en secretaris via eIDAS-gekwalificeerde elektronische handtekening.", + "encodingFormat": "application/pdf", + "contentSize": "1.2 MB" + } + ], + "engagement-record": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "engagement-record" + }, + "slug": "engagement-rvc-q1-pieter", + "meeting": "rvc-vergadering-q1-2025", + "participant": "pieter-van-den-berg", + "speeches": [], + "questionsRaised": [], + "topicsSuggested": [ + { + "title": "Duurzaamheidsrapportage" + } + ], + "speakingDuration": 0, + "engagementScore": 6 + } + ], + "evaluation-response": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "evaluation-response" + }, + "slug": "reactie-evaluatie-acme-rvc-2026-a", + "answers": [ + { + "questionId": "q-strategy-likert", + "dimension": "strategy-and-oversight", + "likertValue": 5 + }, + { + "questionId": "q-dynamics-text", + "dimension": "board-dynamics", + "freeText": "The board is respectful but could challenge management more." + } + ], + "submittedAt": "2026-06-10T09:30:00Z", + "responseToken": "3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d", + "boardEvaluation": "evaluatie-acme-rvc-2026" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "evaluation-response" + }, + "slug": "reactie-evaluatie-acme-rvc-2026-b", + "answers": [ + { + "questionId": "q-strategy-likert", + "dimension": "strategy-and-oversight", + "likertValue": 3 + }, + { + "questionId": "q-information-likert", + "dimension": "information-quality", + "likertValue": 3 + } + ], + "submittedAt": "2026-06-11T11:05:00Z", + "responseToken": "5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f", + "boardEvaluation": "evaluatie-acme-rvc-2026" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "evaluation-response" + }, + "slug": "reactie-evaluatie-rvc-waterschap-amstel-2025-a", + "answers": [ + { + "questionId": "q-strategy-likert", + "dimension": "strategy-and-oversight", + "likertValue": 4 + }, + { + "questionId": "q-strategy-text", + "dimension": "strategy-and-oversight", + "freeText": "More time for scenario discussion ahead of budget decisions." + }, + { + "questionId": "q-chair-likert", + "dimension": "chair-effectiveness", + "likertValue": 3 + } + ], + "submittedAt": "2025-12-05T10:12:00Z", + "responseToken": "8f2b6a1e9d3c4f5a7b6e8d1c2a3f4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a", + "boardEvaluation": "evaluatie-rvc-waterschap-amstel-2025" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "evaluation-response" + }, + "slug": "reactie-evaluatie-rvc-waterschap-amstel-2025-b", + "answers": [ + { + "questionId": "q-strategy-likert", + "dimension": "strategy-and-oversight", + "likertValue": 4 + }, + { + "questionId": "q-composition-likert", + "dimension": "board-composition", + "likertValue": 3 + }, + { + "questionId": "q-chair-likert", + "dimension": "chair-effectiveness", + "likertValue": 4 + } + ], + "submittedAt": "2025-12-08T14:40:00Z", + "responseToken": "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b", + "boardEvaluation": "evaluatie-rvc-waterschap-amstel-2025" + } + ], + "evaluation-template": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "evaluation-template" + }, + "slug": "template-bestuurlijke-effectiviteit", + "title": "Board effectiveness self-evaluation (NL Corporate Governance Code)", + "description": "Default reusable annual board self-evaluation (zelfevaluatie) covering the five standard effectiveness dimensions. Editable per body.", + "dimensions": [ + "strategy-and-oversight", + "board-composition", + "board-dynamics", + "information-quality", + "chair-effectiveness" + ], + "questions": [ + { + "id": "q-strategy-likert", + "dimension": "strategy-and-oversight", + "prompt": "The board sets clear strategic direction and exercises effective oversight of management.", + "type": "likert", + "scaleMin": 1, + "scaleMax": 5 + }, + { + "id": "q-strategy-text", + "dimension": "strategy-and-oversight", + "prompt": "What would most improve the board's strategic oversight?", + "type": "free-text" + }, + { + "id": "q-composition-likert", + "dimension": "board-composition", + "prompt": "The board's composition (skills, diversity, independence) matches the organisation's needs.", + "type": "likert", + "scaleMin": 1, + "scaleMax": 5 + }, + { + "id": "q-composition-text", + "dimension": "board-composition", + "prompt": "What skills or perspectives is the board missing?", + "type": "free-text" + }, + { + "id": "q-dynamics-likert", + "dimension": "board-dynamics", + "prompt": "Board discussions are open, constructive, and every member's voice is heard.", + "type": "likert", + "scaleMin": 1, + "scaleMax": 5 + }, + { + "id": "q-dynamics-text", + "dimension": "board-dynamics", + "prompt": "Describe one dynamic that helps or hinders the board's functioning.", + "type": "free-text" + }, + { + "id": "q-information-likert", + "dimension": "information-quality", + "prompt": "The board receives timely, complete, and understandable information ahead of meetings.", + "type": "likert", + "scaleMin": 1, + "scaleMax": 5 + }, + { + "id": "q-information-text", + "dimension": "information-quality", + "prompt": "What information gap most affects the board's decision-making?", + "type": "free-text" + }, + { + "id": "q-chair-likert", + "dimension": "chair-effectiveness", + "prompt": "The chair runs meetings effectively and ensures balanced participation.", + "type": "likert", + "scaleMin": 1, + "scaleMax": 5 + }, + { + "id": "q-chair-text", + "dimension": "chair-effectiveness", + "prompt": "What is one suggestion for the chair?", + "type": "free-text" + } + ] + } + ], + "geschenk": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "geschenk" + }, + "slug": "gs-congres-uitnodiging", + "recipient": "janneke-de-bruin", + "governanceBody": "rvc-waterschap-amstel", + "type": "invitation", + "giver": "Brancheorganisatie Water", + "description": "Congres met overnachting", + "estimatedValue": 400, + "receivedOn": "2026-02-03", + "decision": "transferred", + "notes": "Deelname overgedragen aan de organisatie; geen persoonlijk voordeel.", + "declaredAt": "2026-02-04" + } + ], + "goal": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "goal" + }, + "slug": "goal-acme-groeidoelstelling-2028", + "title": "Duurzame omzetgroei 2028", + "description": "Structurele omzetgroei realiseren binnen de duurzaamheidsdoelstellingen van de raad van bestuur.", + "horizon": "multi-year", + "body": "raad-van-bestuur-acme-bv", + "owner": "00000000-0000-0000-0000-000000000000", + "startDate": "2026-01-01", + "deadline": "2028-12-31", + "status": "active", + "targetValue": 20, + "currentValue": 6, + "unit": "% omzetgroei" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "goal" + }, + "slug": "goal-acme-mt-operationele-effectiviteit-2026", + "title": "Operationele effectiviteit 2026", + "description": "Procesdoorlooptijden binnen norm brengen als uitvoering van de groeidoelstelling.", + "horizon": "annual", + "body": "managementteam-acme-bv", + "owner": "00000000-0000-0000-0000-000000000000", + "startDate": "2026-01-01", + "deadline": "2026-12-31", + "status": "active", + "targetValue": 90, + "currentValue": 78, + "unit": "% doorlooptijd binnen norm", + "parentGoal": "goal-acme-groeidoelstelling-2028" + } + ], + "governance-body": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "development-team-conduction", + "name": "Development team", + "bodyType": "operational", + "domain": "operations", + "votingDefault": "for-against-abstain", + "active": true, + "termStart": "2026-01-01T00:00:00Z", + "id": "c7d10000-0000-4000-a000-000000000002", + "uuid": "c7d10000-0000-4000-a000-000000000002" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "gemeenteraad-amsterdam", + "name": "Gemeenteraad Amsterdam", + "bodyType": "legislative", + "domain": "municipality", + "votingDefault": "for-against-abstain", + "termStart": "2022-03-16T00:00:00Z", + "termEnd": "2026-03-15T00:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "management-team-conduction", + "name": "Management team", + "bodyType": "operational", + "domain": "operations", + "votingDefault": "for-against-abstain", + "active": true, + "termStart": "2026-01-01T00:00:00Z", + "id": "c7d10000-0000-4000-a000-000000000001", + "uuid": "c7d10000-0000-4000-a000-000000000001" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "managementteam-acme-bv", + "name": "Managementteam ACME B.V.", + "bodyType": "operational", + "domain": "corporate", + "votingDefault": "show-of-hands" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "pub-quiz-conduction", + "name": "Pub quiz", + "bodyType": "operational", + "domain": "operations", + "votingDefault": "for-against-abstain", + "active": true, + "termStart": "2026-01-01T00:00:00Z", + "id": "c7d10000-0000-4000-a000-000000000003", + "uuid": "c7d10000-0000-4000-a000-000000000003" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "raad-van-bestuur-acme-bv", + "name": "Raad van Bestuur ACME B.V.", + "bodyType": "executive-board", + "domain": "corporate", + "votingDefault": "for-against-abstain", + "termStart": "2024-01-01T00:00:00Z", + "termEnd": "2028-12-31T00:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "raad-van-commissarissen-acme-bv", + "name": "Raad van Commissarissen ACME B.V.", + "bodyType": "supervisory-board", + "domain": "corporate", + "votingDefault": "for-against-abstain", + "termStart": "2024-01-01T00:00:00Z", + "termEnd": "2027-12-31T00:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "rvc-waterschap-amstel", + "name": "Raad van Commissarissen Waterschap Amstel, Gooi en Vecht", + "bodyType": "corporate-board", + "domain": "water-authority", + "votingDefault": "for-against-abstain", + "termStart": "2023-01-01T00:00:00Z", + "termEnd": "2026-12-31T00:00:00Z" + } + ], + "governance-body-composition": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body-composition" + }, + "slug": "composition-pub-quiz-development-team", + "composite": "c7d10000-0000-4000-a000-000000000003", + "component": "c7d10000-0000-4000-a000-000000000002", + "compositionType": "direct", + "accessionDate": "2026-01-01", + "label": "Development team plays" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body-composition" + }, + "slug": "composition-pub-quiz-management-team", + "composite": "c7d10000-0000-4000-a000-000000000003", + "component": "c7d10000-0000-4000-a000-000000000001", + "compositionType": "direct", + "accessionDate": "2026-01-01", + "label": "Management team plays" + } + ], + "governing-document": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governing-document" + }, + "slug": "huishoudelijk-reglement-acme-bv", + "type": "internal-regulations", + "citationTitle": "Huishoudelijk reglement ACME B.V.", + "description": "Huishoudelijk reglement van de raad van bestuur, aanvullend op de statuten.", + "governingBody": "raad-van-bestuur-acme-bv", + "isPublic": false, + "status": "in-force", + "currentEffectiveDate": "2025-09-01" + } + ], + "integriteitsbeleid": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "integriteitsbeleid" + }, + "slug": "beleid-rvc-waterschap", + "governanceBody": "rvc-waterschap-amstel", + "ancillaryPositionDisclosureDefault": "internal", + "giftThresholdAmount": 100, + "giftsPublic": false, + "integrityNotificationGroup": "decidesk-compliance" + } + ], + "meeting": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "meeting" + }, + "slug": "directieoverleg-2025-04-14", + "title": "Directieoverleg week 16 — Gemeente Utrecht", + "meetingType": "regular", + "scheduledDate": "2025-04-14T09:00:00Z", + "endDate": "2025-04-14T11:00:00Z", + "location": "Stadskantoor Utrecht, Kamer 3.12", + "meetingMode": "hybrid", + "lifecycle": "draft" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "meeting" + }, + "slug": "pub-quiz-night-2026-09", + "title": "Pub quiz — September 2026", + "type": "c7d10000-0000-4000-a000-000000000031", + "governanceBody": "c7d10000-0000-4000-a000-000000000003", + "meetingType": "regular", + "scheduledDate": "2026-09-18T19:30:00Z", + "endDate": "2026-09-18T21:00:00Z", + "location": "Conduction HQ, kantine", + "meetingMode": "in-person", + "lifecycle": "scheduled", + "quorumRequired": 4, + "isPublic": false, + "id": "c7d10000-0000-4000-a000-000000000041", + "uuid": "c7d10000-0000-4000-a000-000000000041" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "meeting" + }, + "slug": "rvc-vergadering-2025-q2", + "title": "RvC-vergadering Q2 2025", + "meetingType": "regular", + "scheduledDate": "2025-04-17T14:00:00Z", + "endDate": "2025-04-17T16:30:00Z", + "location": "ACME B.V. hoofdkantoor, bestuurskamer", + "meetingMode": "hybrid", + "lifecycle": "closed" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "meeting" + }, + "slug": "rvc-vergadering-q1-2025", + "title": "RvC Vergadering Q1 2025 — Waterschap", + "meetingType": "regular", + "scheduledDate": "2025-02-05T10:00:00Z", + "endDate": "2025-02-05T13:00:00Z", + "location": "Waternet Kantoor, Amstel 1", + "meetingMode": "in-person", + "lifecycle": "closed" + } + ], + "meeting-type": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "meeting-type" + }, + "slug": "meeting-type-pub-quiz-night", + "name": "Pub quiz night", + "governanceBody": "c7d10000-0000-4000-a000-000000000003", + "allowedAgendaItemTypes": [ + "c7d10000-0000-4000-a000-000000000022", + "c7d10000-0000-4000-a000-000000000021" + ], + "defaultQuorum": 4, + "defaultQuorumRule": "majority", + "defaultVotingRule": "for-against-abstain", + "defaultVoteThreshold": "simple-majority", + "defaultDurationMinutes": 90, + "initialLifecycle": "scheduled", + "isPublic": false, + "isDraft": false, + "validFrom": "2026-01-01", + "active": true, + "description": "The Pub quiz body's own meeting kind. It exists in no enum anywhere in decidiq — that is the point: a gremium defined its own meeting type at runtime, with zero code changed.", + "id": "c7d10000-0000-4000-a000-000000000031", + "uuid": "c7d10000-0000-4000-a000-000000000031" + } + ], + "membership": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "membership" + }, + "slug": "m-jan-amstel", + "role": "secretary", + "label": "Raadsgriffier", + "votingWeight": 0, + "startDate": "2021-01-15T00:00:00Z", + "person": "jan-de-vries", + "governanceBody": "rvc-waterschap-amstel", + "post": "post-griffier-amsterdam" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "membership" + }, + "slug": "m-janneke-rvc", + "role": "chair", + "label": "Voorzitter RvC", + "votingWeight": 1, + "startDate": "2022-04-01T00:00:00Z", + "endDate": "2026-04-01T00:00:00Z", + "independenceStatus": "independent", + "otherPositions": [ + "RvC Stedin (vice-voorzitter)", + "Bestuur Stichting Concertgebouw" + ], + "person": "janneke-de-bruin", + "governanceBody": "rvc-waterschap-amstel", + "post": "post-voorzitter-rvc" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "membership" + }, + "slug": "m-mark-rvb", + "role": "member", + "label": "Lid RvB", + "votingWeight": 1, + "startDate": "2020-01-01T00:00:00Z", + "endDate": "2025-12-31T00:00:00Z", + "independenceStatus": "non-independent", + "otherPositions": [ + "Bestuur Branchevereniging Tech NL" + ], + "person": "mark-van-den-berg", + "governanceBody": "rvc-waterschap-amstel" + } + ], + "minutes": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "minutes" + }, + "slug": "notulen-directieoverleg-2025-04-14", + "title": "Verslag Directieoverleg Gemeente Utrecht 14 april 2025", + "lifecycle": "draft", + "version": 1 + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "minutes" + }, + "slug": "notulen-rvc-2025-q2", + "title": "Notulen RvC-vergadering Q2 2025", + "lifecycle": "approved", + "content": "De voorzitter van de Raad van Commissarissen opent de vergadering om 14:00 uur...", + "approvedAt": "2025-05-15T10:00:00Z", + "signedBy": [ + "Voorzitter RvC", + "Secretaris" + ], + "version": 1 + } + ], + "nevenfunctie": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "nevenfunctie" + }, + "slug": "nf-rvc-stedin", + "person": "janneke-de-bruin", + "governanceBody": "rvc-waterschap-amstel", + "organisation": "Stedin", + "role": "RvC vice-voorzitter", + "remunerated": true, + "qualitateQua": false, + "startDate": "2022-01-01", + "declaredAt": "2022-01-10", + "reviewedAt": "2026-06-15", + "lifecycle": "internal" + } + ], + "participant": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "participant" + }, + "slug": "femke-halsema", + "displayName": "Femke Halsema", + "role": "chair", + "email": "f.halsema@amsterdam.nl", + "joinedAt": "2018-05-30T00:00:00Z", + "votingWeight": 1 + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "participant" + }, + "slug": "jan-de-vries", + "displayName": "Jan de Vries", + "role": "secretary", + "email": "j.devries@waterschap.nl", + "joinedAt": "2021-01-15T00:00:00Z", + "votingWeight": 1 + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "participant" + }, + "slug": "marie-janssen", + "displayName": "Marie Janssen", + "role": "member", + "party": "D66", + "email": "m.janssen@amsterdam.nl", + "joinedAt": "2022-03-16T00:00:00Z", + "votingWeight": 1 + } + ], + "person": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "person" + }, + "slug": "femke-halsema", + "name": "Femke Halsema", + "givenName": "Femke", + "familyName": "Halsema", + "gender": "female", + "email": "f.halsema@amsterdam.nl", + "biography": "Burgemeester van Amsterdam, voorzitter van de gemeenteraad." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "person" + }, + "slug": "jan-de-vries", + "name": "Jan de Vries", + "givenName": "Jan", + "familyName": "de Vries", + "gender": "male", + "email": "j.devries@waterschap.nl", + "biography": "Secretaris / griffier." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "person" + }, + "slug": "janneke-de-bruin", + "name": "Janneke de Bruin", + "givenName": "Janneke", + "familyName": "de Bruin", + "gender": "female", + "email": "j.debruin@acme.example", + "biography": "Voorzitter Raad van Commissarissen.", + "nationality": "NL" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "person" + }, + "slug": "marie-janssen", + "name": "Marie Janssen", + "givenName": "Marie", + "familyName": "Janssen", + "gender": "female", + "email": "m.janssen@amsterdam.nl", + "biography": "Raadslid en lid van de VNG-ledenraad." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "person" + }, + "slug": "mark-van-den-berg", + "name": "Mark van den Berg", + "givenName": "Mark", + "familyName": "van den Berg", + "gender": "male", + "email": "m.vandenberg@acme.example", + "biography": "Lid Raad van Bestuur.", + "nationality": "NL" + } + ], + "position-type": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "position-type" + }, + "slug": "position-management-team-chair", + "name": "Chair", + "governanceBody": "c7d10000-0000-4000-a000-000000000001", + "key": "chair", + "seats": 1, + "order": 1, + "allowedHoldTypes": [ + "regular", + "interim", + "acting" + ], + "termDurationMonths": 24, + "maxConsecutiveTerms": 2, + "reappointable": true, + "active": true, + "description": "Chairs the management team. Its allowedHoldTypes admit an interim; the quizmaster's do not admit 'acting' — hold types are configured per position, not globally.", + "id": "c7d10000-0000-4000-a000-000000000012", + "uuid": "c7d10000-0000-4000-a000-000000000012" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "position-type" + }, + "slug": "position-pub-quiz-quizmaster", + "name": "Quizmaster", + "governanceBody": "c7d10000-0000-4000-a000-000000000003", + "key": "quizmaster", + "seats": 1, + "order": 1, + "allowedHoldTypes": [ + "regular", + "interim" + ], + "termDurationMonths": 12, + "maxConsecutiveTerms": 3, + "reappointable": true, + "active": true, + "description": "Runs the quiz and rules on disputed answers. Demonstrates a position declared by its own gremium: the Management team has no quizmaster unless it declares one.", + "id": "c7d10000-0000-4000-a000-000000000011", + "uuid": "c7d10000-0000-4000-a000-000000000011" + } + ], + "post": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "post" + }, + "slug": "post-griffier-amsterdam", + "label": "Raadsgriffier", + "role": "secretary", + "startDate": "2021-01-15T00:00:00Z", + "governanceBody": "gemeenteraad-amsterdam" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "post" + }, + "slug": "post-voorzitter-rvc", + "label": "Voorzitter RvC", + "role": "chair", + "startDate": "2022-04-01T00:00:00Z", + "governanceBody": "rvc-waterschap-amstel" + } + ], + "process-template": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "process-template" + }, + "slug": "corporate-board", + "name": "Corporate Board (BV)", + "description": "Decision process for the management board of a Dutch private limited company (BV).", + "context": "corporate", + "builtIn": true, + "initialState": "draft", + "stateMachine": { + "states": [ + { + "name": "draft" + }, + { + "name": "proposed" + }, + { + "name": "deliberating" + }, + { + "name": "voting" + }, + { + "name": "decided" + }, + { + "name": "enacted" + }, + { + "name": "archived" + } + ], + "transitions": [ + { + "name": "propose", + "from": "draft", + "to": "proposed" + }, + { + "name": "deliberate", + "from": "proposed", + "to": "deliberating" + }, + { + "name": "openVoting", + "from": "deliberating", + "to": "voting", + "chairOnly": true, + "guards": [ + "quorum_met" + ] + }, + { + "name": "decide", + "from": "voting", + "to": "decided" + }, + { + "name": "enact", + "from": "decided", + "to": "enacted" + }, + { + "name": "archive", + "from": "enacted", + "to": "archived" + } + ] + }, + "votingRule": { + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "tieBreakRule": "chair-decides" + }, + "quorumRequired": true, + "quorumRule": "Quorum per the articles of association", + "allowDecideWithoutVote": false + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "process-template" + }, + "slug": "corporate-board-urgent", + "name": "Corporate Board (urgency-enabled)", + "description": "Corporate management board (RvB) process template with the urgent-decision procedure enabled: urgent resolution decided via an expedited 24h written round, ratified by the Raad van Commissarissen (design seed table, corporate column).", + "context": "corporate", + "builtIn": false, + "initialState": "draft", + "stateMachine": { + "states": [ + { + "name": "draft" + }, + { + "name": "proposed" + }, + { + "name": "deliberating" + }, + { + "name": "voting" + }, + { + "name": "decided" + }, + { + "name": "enacted" + }, + { + "name": "archived" + } + ], + "transitions": [ + { + "name": "propose", + "from": "draft", + "to": "proposed" + }, + { + "name": "deliberate", + "from": "proposed", + "to": "deliberating" + }, + { + "name": "openVoting", + "from": "deliberating", + "to": "voting", + "chairOnly": true, + "guards": [ + "quorum_met" + ] + }, + { + "name": "decide", + "from": "voting", + "to": "decided" + }, + { + "name": "enact", + "from": "decided", + "to": "enacted" + }, + { + "name": "archive", + "from": "enacted", + "to": "archived" + } + ] + }, + "votingRule": { + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "tieBreakRule": "chair-decides" + }, + "quorumRequired": true, + "quorumRule": "Quorum per the articles of association", + "allowDecideWithoutVote": false, + "urgencyPolicy": { + "allowedTriggerRoles": [ + "chair", + "secretary" + ], + "minimumNoticeFloorHours": 12, + "responseDeadlineHours": { + "min": 4, + "max": 72 + }, + "ratificationRequired": true, + "ratifyingBody": "raad-van-commissarissen-acme-bv" + } + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "process-template" + }, + "slug": "operational-team", + "name": "Operational Team", + "description": "Lightweight decision process for an operational/management team; formal voting rounds are optional.", + "context": "operations", + "builtIn": true, + "initialState": "draft", + "stateMachine": { + "states": [ + { + "name": "draft" + }, + { + "name": "proposed" + }, + { + "name": "deliberating" + }, + { + "name": "decided" + }, + { + "name": "enacted" + }, + { + "name": "archived" + } + ], + "transitions": [ + { + "name": "propose", + "from": "draft", + "to": "proposed" + }, + { + "name": "deliberate", + "from": "proposed", + "to": "deliberating" + }, + { + "name": "decide", + "from": "deliberating", + "to": "decided" + }, + { + "name": "enact", + "from": "decided", + "to": "enacted" + }, + { + "name": "archive", + "from": "enacted", + "to": "archived" + } + ] + }, + "votingRule": { + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "tieBreakRule": "rejected" + }, + "quorumRequired": false, + "quorumRule": "No formal quorum", + "allowDecideWithoutVote": true + } + ], + "rooster-regel": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "rooster-regel" + }, + "slug": "rooster-regel-rvc-dewit", + "schedule": "rooster-rvc-acme", + "membership": "00000000-0000-0000-0000-000000000000", + "personName": "P. de Wit", + "role": "chair", + "termNumber": 2, + "endTermDate": "2026-11-01", + "reappointable": false, + "rappelStatus": "reminder-6-months" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "rooster-regel" + }, + "slug": "rooster-regel-rvc-smit", + "schedule": "rooster-rvc-acme", + "membership": "00000000-0000-0000-0000-000000000000", + "personName": "A. Smit", + "role": "member", + "termNumber": 1, + "endTermDate": "2028-03-15", + "reappointable": true + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "rooster-regel" + }, + "slug": "rooster-regel-rvc-vanduin", + "schedule": "rooster-rvc-acme", + "membership": "00000000-0000-0000-0000-000000000000", + "personName": "J. van Duin", + "role": "member", + "termNumber": 1, + "endTermDate": "2030-09-10", + "reappointable": true + } + ], + "rooster-van-aftreden": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "rooster-van-aftreden" + }, + "slug": "rooster-rvc-acme", + "body": "raad-van-commissarissen-acme-bv", + "generatedOn": "2026-07-01T09:00:00Z", + "generatedBy": "Griffie", + "publicationDate": "2026-07-02T09:00:00Z" + } + ], + "termijn-regeling": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "termijn-regeling" + }, + "slug": "termijn-regeling-rvc-acme", + "body": "raad-van-commissarissen-acme-bv", + "termDurationMonths": 48, + "maxConsecutivePeriods": 2, + "notes": "Statutair: eenmaal herbenoembaar (art. 12 statuten)." + } + ], + "voting-round": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "voting-round" + }, + "slug": "pub-quiz-2026-09-q1-vote", + "votingMethod": "for-against-abstain", + "isSecret": false, + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "tieBreakRule": "chair-decides", + "openedAt": "2026-09-18T19:40:00Z", + "id": "c7d10000-0000-4000-a000-000000000061", + "uuid": "c7d10000-0000-4000-a000-000000000061" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "voting-round" + }, + "slug": "pub-quiz-2026-09-q2-vote", + "votingMethod": "for-against-abstain", + "isSecret": false, + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "tieBreakRule": "chair-decides", + "openedAt": "2026-09-18T19:50:00Z", + "id": "c7d10000-0000-4000-a000-000000000062", + "uuid": "c7d10000-0000-4000-a000-000000000062" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "voting-round" + }, + "slug": "pub-quiz-2026-09-q3-vote", + "votingMethod": "show-of-hands", + "isSecret": false, + "voteThreshold": "simple-majority", + "abstentionHandling": "count", + "tieBreakRule": "chair-decides", + "openedAt": "2026-09-18T20:00:00Z", + "id": "c7d10000-0000-4000-a000-000000000063", + "uuid": "c7d10000-0000-4000-a000-000000000063" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "voting-round" + }, + "slug": "stemming-investering-acme-rvb-geheim", + "votingMethod": "for-against-abstain", + "isSecret": true, + "openedAt": "2026-04-18T15:00:00Z", + "closedAt": "2026-04-18T15:20:00Z", + "quorumWith": true, + "result": "adopted", + "votesFor": 3, + "votesAgainst": 0, + "votesAbstain": 0, + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "decisionStage": "stage-investering-acme-2-dec" + } + ] + } + } + }, + "paths": {}, + "components": {} +} diff --git a/lib/Settings/profiles/municipality.json b/lib/Settings/profiles/municipality.json new file mode 100644 index 000000000..d85bb65a7 --- /dev/null +++ b/lib/Settings/profiles/municipality.json @@ -0,0 +1,4111 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Decidiq example set: Municipality", + "version": "1.0.0", + "description": "A council with committees and factions. Motions, commitments, information letters and a regulations register." + }, + "x-openregister": { + "type": "profile", + "app": "decidiq", + "profile": { + "id": "municipality", + "label": "Municipality", + "description": "A council with committees and factions. Motions, commitments, information letters and a regulations register.", + "order": 1, + "objectCount": 199 + }, + "description": "An example set an operator picks in the first-time setup wizard (ADR-042). NEVER imported on install: the register.d fragments declare schemas only, so a bare install has zero objects. Every object carries @self.configuration/register/schema so the import resolves the live decidiq register WITHOUT this descriptor declaring components.registers. That is deliberate and load-bearing: ImportHandler::importRegister() calls setApplication($appId) unconditionally on an existing register, so a descriptor that declared the register would re-point the decidiq register at this profile config id and hydrate over its authorization baseline. Verified on a live instance: importing this shape left application=decidiq, version and authorization byte-identical. Import is idempotent by slug, so loading a profile twice adds nothing. Descriptors live in this SUBDIRECTORY on purpose: RegisterDescriptorService scans lib/Settings/*.json non-recursively and matches descriptors by declared register slug, so four profile files in lib/Settings would collide with each other and with decidesk_register.json.", + "seedData": { + "description": "Example objects for the municipality set.", + "objects": { + "action-item": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "action-item" + }, + "slug": "actie-besluiten-ori-publicatie", + "title": "Besluiten raadsvergadering publiceren via ORI-koppeling", + "description": "Informatiemanager controleert ORI-export en bevestigt succesvolle aanlevering bij PLOOI.", + "assignee": "Informatiemanager", + "dueDate": "2025-03-22T00:00:00Z", + "taskStatus": "overdue" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "action-item" + }, + "slug": "actie-bestemmingsplan-publiceren", + "title": "Bestemmingsplan Groningen-Noord publiceren op ruimtelijkeplannen.nl", + "assignee": "Ruimtelijke Ordening", + "dueDate": "2025-04-10T00:00:00Z", + "taskStatus": "overdue" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "action-item" + }, + "slug": "actie-communicatie-begroting-2026", + "title": "Begroting 2026 communiceren naar inwoners", + "assignee": "Communicatieafdeling", + "dueDate": "2025-05-01T00:00:00Z", + "taskStatus": "completed", + "completedAt": "2025-04-25T14:30:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "action-item" + }, + "slug": "actie-fusie-dorpsraden-convenant", + "title": "Convenant fusie dorpsraden Noord en Oost opstellen en laten ondertekenen", + "description": "Gemeentelijke contactpersoon stelt convenant op in samenspraak met beide dorpsraden.", + "assignee": "Beleidsmedewerker Participatie", + "dueDate": "2025-10-01T00:00:00Z", + "taskStatus": "open" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "action-item" + }, + "slug": "actie-notulen-distribueren", + "title": "Definitieve notulen raadsvergadering 20 maart distribueren", + "description": "Griffier verstuurt vastgestelde notulen aan alle raadsleden en publiceert op gemeentelijke website.", + "assignee": "Griffier", + "dueDate": "2025-04-11T00:00:00Z", + "taskStatus": "completed", + "completedAt": "2025-04-11T09:30:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "action-item" + }, + "slug": "actie-plan-zonnepanelen", + "title": "Plan van aanpak zonnepanelen gemeentelijke gebouwen opstellen", + "description": "College presenteert plan voor 1 januari 2026 conform aangenomen motie.", + "assignee": "Wethouder Duurzaamheid", + "dueDate": "2026-01-01T00:00:00Z", + "taskStatus": "open" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "action-item" + }, + "slug": "actie-woningbouw-uitvoeringsplan", + "title": "Uitvoeringsplan Woningbouwplan Oost opstellen", + "description": "College stelt uitvoeringsplan op inclusief fasering, budgetten en planning.", + "assignee": "Wethouder Wonen", + "dueDate": "2025-07-01T00:00:00Z", + "taskStatus": "in-progress" + } + ], + "advice-request": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "advice-request" + }, + "slug": "adviesaanvraag-inkoopbeleid-wmo", + "subject": "Herziening inkoopbeleid Wmo-ondersteuning", + "question": "Welke gevolgen heeft het voorgenomen inkoopbeleid voor cliënten en mantelzorgers?", + "requestingBody": "00000000-0000-0000-0000-000000000000", + "advisoryBody": "adviesraad-sociaal-domein", + "sentDate": "2026-03-02", + "requestedByDate": "2026-04-13", + "lifecycle": "advice-issued", + "relatedDecision": "00000000-0000-0000-0000-000000000000", + "advisoryStage": "00000000-0000-0000-0000-000000000000" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "advice-request" + }, + "slug": "adviesaanvraag-jongerenhuisvesting", + "subject": "Beleidsnota jongerenhuisvesting 2027–2031", + "question": "Sluit de nota aan bij de woonbehoeften van jongeren van 18–27 jaar?", + "requestingBody": "gemeenteraad-amsterdam", + "advisoryBody": "jongerenraad", + "sentDate": "2026-05-04", + "requestedByDate": "2026-06-15", + "lifecycle": "in-progress" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "advice-request" + }, + "slug": "adviesaanvraag-skatepark-locatie", + "subject": "Locatiekeuze skatepark centrum", + "question": "Welke van de drie kandidaat-locaties heeft de voorkeur van jongeren?", + "requestingBody": "gemeenteraad-amsterdam", + "advisoryBody": "jongerenraad", + "sentDate": "2026-01-12", + "requestedByDate": "2026-02-16", + "lifecycle": "completed", + "relatedDecision": "00000000-0000-0000-0000-000000000000", + "accountabilityText": "De raad kiest locatie B in afwijking van het advies (locatie A) vanwege geluidsnormen; met de jongerenraad is een evaluatie na één jaar afgesproken.", + "accountabilityDate": "2026-03-24", + "publicationDate": "2026-03-25T09:00:00Z" + } + ], + "advies": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "advies" + }, + "slug": "advies-inkoopbeleid-wmo", + "adviceRequest": "adviesaanvraag-inkoopbeleid-wmo", + "tenor": "positive-with-reservations", + "summary": "De adviesraad adviseert positief, mits de continuïteit van lopende ondersteuning wordt geborgd en cliënten actief worden geïnformeerd.", + "adviceDate": "2026-04-10", + "recordedBy": "00000000-0000-0000-0000-000000000000", + "publicationDate": "2026-04-12T09:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "advies" + }, + "slug": "advies-skatepark-locatie", + "adviceRequest": "adviesaanvraag-skatepark-locatie", + "tenor": "negative", + "summary": "De jongerenraad adviseert negatief over locatie B en positief over locatie A vanwege bereikbaarheid.", + "adviceDate": "2026-02-14", + "recordedBy": "00000000-0000-0000-0000-000000000000", + "publicationDate": "2026-03-25T09:00:00Z" + } + ], + "agenda-item": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "begroting-2026-bespreking", + "title": "Kadernota begroting 2026", + "itemType": "discussion", + "orderNumber": 4, + "estimatedDuration": 60, + "description": "Eerste bespreking van de financiële kaders voor begrotingsjaar 2026" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "interpellatie-cultuurhuis-2025-01-15", + "title": "Interpellatie: subsidieverlening cultuurhuis", + "itemType": "discussion", + "orderNumber": 8, + "estimatedDuration": 45, + "description": "Eigen agendapunt voor het geagendeerde interpellatieverzoek int-subsidie-cultuurhuis (vragenuur-interpellatie REQ-VRI-012).", + "meeting": "raadsvergadering-2025-01-15" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "interpellatie-stationsgebied-2025", + "title": "Interpellatie: veiligheid stationsgebied", + "itemType": "discussion", + "orderNumber": 7, + "estimatedDuration": 45, + "description": "Eigen agendapunt voor het toegelaten interpellatieverzoek int-veiligheid-stationsgebied (vragenuur-interpellatie REQ-VRI-012); een interpellatie krijgt een eigen agendapunt, nooit samengevoegd met het vragenuur.", + "meeting": "raadsvergadering-2025-01-15" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "jaarrekening-2024", + "title": "Jaarrekening 2024 — ter goedkeuring", + "itemType": "decision", + "orderNumber": 3, + "estimatedDuration": 45, + "description": "Bespreking en vaststelling van de jaarrekening over het boekjaar 2024" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "lijst-ingekomen-stukken-2025-01-15", + "title": "Lijst ingekomen stukken", + "itemType": "decision", + "orderNumber": 5, + "estimatedDuration": 10, + "description": "Hamerstuk-verzamelagendapunt voor de lijst ingekomen stukken; de griffie-routeringsadviezen worden en bloc bekrachtigd via de hamerstuk-flow (agenda-live-management REQ-LIV-003). AgendaItem draagt geen tag-veld, zodat 'hamerstuk' hier conventioneel via itemType 'decision' + deze omschrijving is vastgelegd.", + "meeting": "raadsvergadering-2025-01-15" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "notulen-2024-12-18", + "title": "Vaststellen notulen vergadering 18 december 2024", + "itemType": "decision", + "orderNumber": 2, + "estimatedDuration": 10, + "isRecurring": true + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "opening-raad-2025-01-15", + "title": "Opening vergadering", + "itemType": "informational", + "orderNumber": 1, + "estimatedDuration": 5 + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "rondvraag", + "title": "Rondvraag", + "itemType": "informational", + "orderNumber": 99, + "estimatedDuration": 10, + "isRecurring": true + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "vragenuur-2025-01-15", + "title": "Vragenuur", + "itemType": "discussion", + "orderNumber": 6, + "estimatedDuration": 30, + "description": "Vragenuur van de raad (Reglement van Orde): raadsleden stellen mondelinge vragen aan de portefeuillehouders. Toegelaten mondelinge vragen worden op dit agendapunt ingepland (vragenuur-interpellatie REQ-VRI-004); de spreektijdklok blijft bij digital-meetings-and-recurrence REQ-STM. AgendaItem draagt geen tag-veld; 'vragenuur' is hier conventioneel via itemType 'discussion' + deze omschrijving vastgelegd.", + "meeting": "raadsvergadering-2025-01-15" + } + ], + "approval-route": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "approval-route" + }, + "slug": "collegeadvies-standaard", + "name": "Collegeadvies — standaard parafering", + "subjectType": "collegeadvies", + "isDefault": true, + "description": "Advies, twee paraferingen en een accordering. The shape a Dutch collegeadvies travels before it reaches the college.", + "steps": [ + { + "order": 1, + "stageType": "advisory", + "actorType": "role", + "actor": "juridisch-adviseur", + "mandatory": true, + "label": "Juridisch advies" + }, + { + "order": 2, + "stageType": "endorsement", + "actorType": "role", + "actor": "afdelingshoofd", + "mandatory": true, + "label": "Parafering afdelingshoofd" + }, + { + "order": 3, + "stageType": "endorsement", + "actorType": "role", + "actor": "concerncontroller", + "mandatory": false, + "label": "Parafering concerncontrol" + }, + { + "order": 4, + "stageType": "decisive", + "actorType": "role", + "actor": "gemeentesecretaris", + "mandatory": true, + "label": "Accordering gemeentesecretaris" + } + ] + } + ], + "bevoegdheidstoedeling": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "bevoegdheidstoedeling" + }, + "slug": "delegatie-uitwerkingsplannen", + "type": "delegation", + "delegans": "gemeenteraad-amsterdam", + "delegatarisBody": "00000000-0000-0000-0000-000000000000", + "subject": "Vaststellen van uitwerkingsplannen als bedoeld in art. 3.6 Wro", + "beperkingen": "Uitsluitend binnen door de raad vastgestelde kaders", + "subMandatePermitted": false, + "statutoryBasis": [ + "Awb art. 10:13", + "Wro art. 3.6" + ], + "decision": "00000000-0000-0000-0000-000000000000", + "validFrom": "2026-01-01", + "status": "effective", + "publicationDate": "2026-01-05T09:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "bevoegdheidstoedeling" + }, + "slug": "machtiging-woo-vertegenwoordiging", + "type": "authorisation", + "delegans": "00000000-0000-0000-0000-000000000000", + "delegateRole": "juridisch adviseur team Recht", + "delegatePerson": "00000000-0000-0000-0000-000000000000", + "subject": "Vertegenwoordiging bij Woo-bezwaarprocedures", + "subMandatePermitted": false, + "statutoryBasis": [ + "Awb art. 10:3" + ], + "decision": "00000000-0000-0000-0000-000000000000", + "validFrom": "2025-01-01", + "validTo": "2026-01-01", + "status": "withdrawn", + "withdrawnBy": "00000000-0000-0000-0000-000000000000", + "publicationDate": "2025-01-10T09:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "bevoegdheidstoedeling" + }, + "slug": "mandaat-subsidies-secretaris", + "type": "mandate", + "delegans": "00000000-0000-0000-0000-000000000000", + "delegateRole": "gemeentesecretaris", + "subject": "Beslissen op subsidieaanvragen tot het genoemde plafond", + "financialCeiling": 25000, + "beperkingen": "Geen subsidies met precedentwerking", + "subMandatePermitted": true, + "statutoryBasis": [ + "Awb art. 10:3", + "Asv 2026 art. 4" + ], + "decision": "00000000-0000-0000-0000-000000000000", + "validFrom": "2026-01-01", + "status": "effective", + "publicationDate": "2026-01-05T09:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "bevoegdheidstoedeling" + }, + "slug": "ondermandaat-subsidies-samenleving", + "type": "mandate", + "delegansDescription": "gemeentesecretaris", + "delegateRole": "afdelingshoofd Samenleving", + "subject": "Beslissen op subsidieaanvragen binnen het programma Samenleving", + "financialCeiling": 5000, + "beperkingen": "Uitsluitend reguliere subsidieregelingen", + "subMandatePermitted": false, + "statutoryBasis": [ + "Awb art. 10:9" + ], + "decision": "00000000-0000-0000-0000-000000000000", + "parentAllocation": "mandaat-subsidies-secretaris", + "validFrom": "2026-02-01", + "validTo": "2026-08-15", + "status": "effective", + "publicationDate": "2026-02-05T09:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "bevoegdheidstoedeling" + }, + "slug": "volmacht-inkoop-teamleider", + "type": "power-of-attorney", + "delegansDescription": "burgemeester", + "delegateRole": "teamleider Inkoop", + "subject": "Aangaan van privaatrechtelijke rechtshandelingen voor inkoop", + "financialCeiling": 50000, + "beperkingen": "Binnen het vastgestelde inkoopbeleid", + "subMandatePermitted": false, + "statutoryBasis": [ + "BW art. 3:60", + "Gemeentewet art. 171" + ], + "decision": "00000000-0000-0000-0000-000000000000", + "validFrom": "2026-03-01", + "status": "draft" + } + ], + "body-participation": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "body-participation" + }, + "slug": "deelname-noorderbrug-noz", + "sharedBody": "bestuur-noz-organisatie", + "participant": "gemeenteraad-noorderbrug", + "seats": 2, + "votingWeight": 2, + "accessionDate": "2015-01-01T00:00:00Z", + "label": "Deelnemer per oprichting" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "body-participation" + }, + "slug": "deelname-oostwoud-noz", + "sharedBody": "bestuur-noz-organisatie", + "participant": "gemeenteraad-oostwoud", + "seats": 2, + "votingWeight": 2, + "accessionDate": "2015-01-01T00:00:00Z", + "label": "Deelnemer per oprichting" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "body-participation" + }, + "slug": "deelname-zuidermeer-noz", + "sharedBody": "bestuur-noz-organisatie", + "participant": "gemeenteraad-zuidermeer", + "seats": 1, + "votingWeight": 1, + "accessionDate": "2015-01-01T00:00:00Z", + "label": "Deelnemer per oprichting" + } + ], + "conflict-of-interest": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "conflict-of-interest" + }, + "slug": "coi-david-r008", + "boardMember": "david-cohen-audit-noord", + "agendaItem": "r-2025-008-audit-charter", + "declarationType": "none", + "actionTaken": "no-action-needed", + "declarationTimestamp": "2025-06-04T10:05:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "conflict-of-interest" + }, + "slug": "coi-rachid-q3", + "boardMember": "rachid-el-amrani-audit-noord", + "declarationType": "competing-business", + "description": "Tweede bestuursfunctie bij vergelijkbare wooncorporatie.", + "severity": "material", + "actionTaken": "recused-from-discussion", + "declarationTimestamp": "2025-06-04T10:10:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "conflict-of-interest" + }, + "slug": "coi-wethouder-vastgoedbelang", + "boardMember": "m-marie-amsterdam", + "declarationType": "financial-interest", + "description": "Lid meldt een financieel belang in een vastgoedontwikkeling die onderwerp is van het agendapunt en onthoudt zich van beraadslaging en stemming.", + "severity": "material", + "actionTaken": "recused-from-vote", + "declarationTimestamp": "2026-06-15T19:05:00Z" + } + ], + "contact-detail": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "contact-detail" + }, + "slug": "cd-amsterdam-address", + "type": "address", + "value": "Amstel 1, Amsterdam", + "label": "Stadhuis", + "governanceBody": "gemeenteraad-amsterdam" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "contact-detail" + }, + "slug": "cd-femke-email", + "type": "email", + "value": "f.halsema@amsterdam.nl", + "label": "Werk", + "person": "femke-halsema" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "contact-detail" + }, + "slug": "cd-femke-phone", + "type": "phone", + "value": "+31 20 624 1111", + "label": "Bestuurssecretariaat", + "person": "femke-halsema" + } + ], + "cyclus-stap": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "cyclus-stap" + }, + "slug": "begroting-2027-gemeenteraad", + "cyclus": "pc-cyclus-2026-gemeenteraad", + "sequence": 5, + "stepType": "begroting", + "label": "Programmabegroting", + "concernsYear": 2027, + "deliveryDeadline": "2026-09-15", + "technicalQuestionsStart": "2026-09-16", + "technicalQuestionsEnd": "2026-10-05", + "handlingCommittee": "00000000-0000-0000-0000-000000000000", + "committeeDate": "2026-10-20", + "decisionMakingBody": "gemeenteraad-amsterdam", + "handlingDate": "2026-11-05", + "documentSlots": [ + { + "name": "Programmabegroting", + "required": true, + "file": "Programmabegroting 2027 (concept).pdf" + }, + { + "name": "Aanbiedingsbrief", + "required": true + }, + { + "name": "Beantwoording technische vragen", + "required": false + } + ], + "status": "planned" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "cyclus-stap" + }, + "slug": "berap-1-2026-gemeenteraad", + "cyclus": "pc-cyclus-2026-gemeenteraad", + "sequence": 2, + "stepType": "berap", + "label": "Eerste bestuursrapportage (berap-1)", + "concernsYear": 2026, + "deliveryDeadline": "2026-05-01", + "decisionMakingBody": "gemeenteraad-amsterdam", + "handlingDate": "2026-06-10", + "documentSlots": [ + { + "name": "Bestuursrapportage", + "required": true + } + ], + "status": "completed" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "cyclus-stap" + }, + "slug": "berap-2-2026-gemeenteraad", + "cyclus": "pc-cyclus-2026-gemeenteraad", + "sequence": 4, + "stepType": "berap", + "label": "Tweede bestuursrapportage (berap-2)", + "concernsYear": 2026, + "deliveryDeadline": "2026-07-10", + "decisionMakingBody": "gemeenteraad-amsterdam", + "handlingDate": "2026-11-04", + "documentSlots": [ + { + "name": "Bestuursrapportage", + "required": true + } + ], + "status": "planned" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "cyclus-stap" + }, + "slug": "jaarrekening-2025-gemeenteraad", + "cyclus": "pc-cyclus-2026-gemeenteraad", + "sequence": 1, + "stepType": "jaarrekening", + "label": "Jaarrekening", + "concernsYear": 2025, + "deliveryDeadline": "2026-04-15", + "decisionMakingBody": "gemeenteraad-amsterdam", + "handlingDate": "2026-07-02", + "documentSlots": [ + { + "name": "Jaarrekening", + "required": true, + "file": "00000000-0000-0000-0000-000000000000" + }, + { + "name": "Accountantsverslag", + "required": true + } + ], + "agendaItem": "00000000-0000-0000-0000-000000000000", + "decision": "00000000-0000-0000-0000-000000000000", + "status": "adopted", + "outcome": "vastgesteld" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "cyclus-stap" + }, + "slug": "kadernota-2027-gemeenteraad", + "cyclus": "pc-cyclus-2026-gemeenteraad", + "sequence": 3, + "stepType": "kadernota", + "label": "Kadernota", + "concernsYear": 2027, + "deliveryDeadline": "2026-05-15", + "decisionMakingBody": "gemeenteraad-amsterdam", + "handlingDate": "2026-07-02", + "documentSlots": [ + { + "name": "Kadernota", + "required": true + } + ], + "agendaItem": "00000000-0000-0000-0000-000000000000", + "status": "in-progress" + } + ], + "cyclus-template": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "cyclus-template" + }, + "slug": "municipal-pc-cyclus", + "name": "Gemeentelijke P&C-cyclus", + "context": "legislative", + "builtIn": true, + "steps": [ + { + "stepType": "jaarrekening", + "label": "Jaarrekening", + "subjectYearOffset": -1, + "deliveryDeadline": "04-15", + "handlingDate": "07-02", + "documentSlots": [ + { + "name": "Jaarrekening", + "required": true + }, + { + "name": "Accountantsverslag", + "required": true + } + ] + }, + { + "stepType": "berap", + "label": "Eerste bestuursrapportage (berap-1)", + "subjectYearOffset": 0, + "deliveryDeadline": "05-01", + "handlingDate": "06-10", + "documentSlots": [ + { + "name": "Bestuursrapportage", + "required": true + } + ] + }, + { + "stepType": "kadernota", + "label": "Kadernota", + "subjectYearOffset": 1, + "deliveryDeadline": "05-15", + "handlingDate": "07-02", + "documentSlots": [ + { + "name": "Kadernota", + "required": true + } + ] + }, + { + "stepType": "berap", + "label": "Tweede bestuursrapportage (berap-2)", + "subjectYearOffset": 0, + "deliveryDeadline": "09-20", + "handlingDate": "11-04", + "documentSlots": [ + { + "name": "Bestuursrapportage", + "required": true + } + ] + }, + { + "stepType": "begroting", + "label": "Programmabegroting", + "subjectYearOffset": 1, + "deliveryDeadline": "09-15", + "technicalQuestionsStart": "09-16", + "technicalQuestionsEnd": "10-05", + "committeeDate": "10-20", + "handlingDate": "11-05", + "documentSlots": [ + { + "name": "Programmabegroting", + "required": true + }, + { + "name": "Aanbiedingsbrief", + "required": true + }, + { + "name": "Beantwoording technische vragen", + "required": false + } + ] + } + ] + } + ], + "decision": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "amendement-cultuursubsidie", + "decisionType": "amendment", + "title": "Amendement Cultuursubsidie verhogen", + "text": "De raad besluit post 6.1 (cultuursubsidies) in de programmabegroting te verhogen met €50.000, ten laste van de post onvoorzien.", + "proposer": "Fatima El-Amrani", + "proposedText": "Verhoog post 6.1 met €50.000", + "lifecycle": "decided", + "outcome": "adopted", + "decisionDate": "2025-04-10T21:05:00Z", + "isPublished": "public", + "amends": "motie-duurzaamheid-2025" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "benoeming-lid-auditcommissie", + "decisionType": "appointment", + "title": "Benoeming lid auditcommissie", + "text": "Voordracht van mevrouw M. Janssen als lid van de auditcommissie, vanwege gewenste financiële expertise.", + "lifecycle": "proposed", + "targetBody": "auditcommissie-provincie-nh", + "targetPosts": [], + "targetRole": "member", + "candidates": [ + { + "person": "marie-janssen", + "notes": "Financiële expertise gewenst in de auditcommissie." + } + ], + "nominatingParty": { + "type": "politicalGroup", + "name": "D66" + }, + "appointedMemberships": [], + "isPublished": "internal" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "benoeming-voorzitter-auditcommissie-ingetrokken", + "decisionType": "appointment", + "title": "Benoeming voorzitter auditcommissie (ingetrokken)", + "text": "Voordracht van de heer K. Bakker als voorzitter van de auditcommissie; kandidaat heeft zich teruggetrokken voor behandeling.", + "lifecycle": "withdrawn", + "targetBody": "auditcommissie-provincie-nh", + "targetPosts": [], + "targetRole": "chair", + "candidates": [ + { + "externalName": "K. Bakker", + "notes": "Kandidaat trekt zich terug voor behandeling." + } + ], + "nominatingParty": { + "type": "politicalGroup", + "name": "GroenLinks" + }, + "appointedMemberships": [], + "isPublished": "internal" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "besluit-amendement-cultuursubsidie-afgewezen", + "decisionType": "meeting-outcome", + "title": "Amendement verhoging cultuursubsidie — niet aanvaard", + "text": "Het amendement tot verhoging van het cultuursubsidiebudget 2026 met €75.000 wordt niet aanvaard.", + "decisionDate": "2025-04-10T21:00:00Z", + "outcome": "rejected", + "isPublished": "internal", + "lifecycle": "decided" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "besluit-begroting-2026", + "decisionType": "meeting-outcome", + "title": "Vaststelling Programmabegroting 2026", + "text": "De gemeenteraad van Westerkwartier stelt de programmabegroting 2026 vast.", + "decisionDate": "2025-04-10T21:38:00Z", + "outcome": "adopted", + "isPublished": "public", + "publishedAt": "2025-04-11T09:00:00Z", + "legalBasis": "Gemeentewet art. 189", + "lifecycle": "enacted", + "enactedAt": "2025-04-11T09:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "besluit-begroting-2027", + "decisionType": "meeting-outcome", + "title": "Vaststelling Programmabegroting 2027", + "text": "De gemeenteraad stelt de programmabegroting 2027 vast conform het raadsvoorstel van het college.", + "decisionDate": "2026-04-15T19:30:00Z", + "outcome": "adopted", + "isPublished": "public", + "legalBasis": "Gemeentewet art. 189", + "lifecycle": "enacted", + "enactedAt": "2026-04-16T09:00:00Z", + "supersedes": [ + "besluit-begroting-2026" + ], + "route": [ + "stage-begroting-2027-1-prep", + "stage-begroting-2027-2-adv", + "stage-begroting-2027-3-dec" + ] + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "besluit-bestemmingsplan-groningen-noord", + "decisionType": "meeting-outcome", + "title": "Vaststelling bestemmingsplan Groningen-Noord", + "text": "De raad stelt het bestemmingsplan Groningen-Noord ongewijzigd vast.", + "decisionDate": "2025-03-27T20:45:00Z", + "outcome": "adopted", + "isPublished": "internal", + "legalBasis": "Wet ruimtelijke ordening art. 3.1", + "lifecycle": "decided" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "besluit-duurzaamheid-2025", + "decisionType": "meeting-outcome", + "title": "Motie Duurzaamheid aangenomen", + "text": "De raad verzoekt het college een plan van aanpak zonnepanelen te presenteren voor 1 januari 2026.", + "decisionDate": "2025-04-10T21:05:00Z", + "outcome": "adopted", + "isPublished": "public", + "publishedAt": "2025-04-11T09:00:00Z", + "lifecycle": "enacted", + "enactedAt": "2025-04-11T09:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "besluit-duurzaamheidsagenda-2026", + "decisionType": "meeting-outcome", + "title": "Vaststelling Duurzaamheidsagenda 2026", + "text": "De raad stelt de Duurzaamheidsagenda Westerkwartier 2026 vast en stelt €200.000 beschikbaar voor uitvoering van de daarin opgenomen maatregelen.", + "decisionDate": "2025-03-20T20:45:00Z", + "outcome": "adopted", + "isPublished": "public", + "publishedAt": "2025-03-21T09:00:00Z", + "legalBasis": "Gemeentewet art. 147", + "lifecycle": "enacted", + "enactedAt": "2025-03-21T09:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "besluit-fusie-dorpsraden", + "decisionType": "meeting-outcome", + "title": "Instemming fusie dorpsraden Noord en Oost per 1 januari 2026", + "text": "De raad stemt in met de samenvoeging van dorpsraad Noord en dorpsraad Oost tot één dorpsraad Noord-Oost, ingaande 1 januari 2026.", + "decisionDate": "2025-04-10T20:30:00Z", + "outcome": "adopted", + "isPublished": "public", + "publishedAt": "2025-04-11T08:30:00Z", + "lifecycle": "enacted", + "enactedAt": "2025-04-11T08:30:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "besluit-vaststelling-rvo-amsterdam", + "decisionType": "resolution", + "title": "Besluit vaststelling reglement van orde gemeenteraad Amsterdam", + "text": "Besluit van de gemeenteraad van Amsterdam tot vaststelling van het reglement van orde (Gemeentewet art. 16).", + "decisionDate": "2023-03-01", + "outcome": "adopted" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "besluit-verordening-parkeren-2026", + "decisionType": "resolution", + "title": "Verordening parkeren 2026", + "text": "Vaststelling van de verordening parkeren 2026, voortvloeiend uit de bespreking van de kadernota begroting 2026.", + "decisionDate": "2026-06-15", + "outcome": "adopted", + "meeting": "raadsvergadering-2025-01-15", + "agendaItem": "begroting-2026-bespreking" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "besluit-woningbouwplan-oost", + "decisionType": "meeting-outcome", + "title": "Vaststelling Woningbouwplan Oost 2025-2030", + "text": "De gemeenteraad van Westerkwartier stelt het Woningbouwplan Oost 2025-2030 vast en machtigt het college tot uitvoering conform bijgaande planning en budgettering.", + "decisionDate": "2025-03-20T21:15:00Z", + "outcome": "adopted", + "isPublished": "public", + "publishedAt": "2025-03-21T09:00:00Z", + "legalBasis": "Wet ruimtelijke ordening art. 3.1", + "lifecycle": "enacted", + "enactedAt": "2025-03-21T09:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "motie-duurzaamheid-2025", + "decisionType": "motion", + "title": "Motie Duurzaamheid: zonnepanelen op gemeentelijke daken", + "text": "De raad verzoekt het college om voor 1 januari 2026 een concreet plan van aanpak op te stellen voor de plaatsing van zonnepanelen op alle gemeentelijke daken, inclusief een kostenraming en tijdlijn.", + "motionType": "motion", + "proposer": "Roos de Vries", + "lifecycle": "decided", + "outcome": "adopted", + "isPublished": "public", + "submittedAt": "2025-04-10T19:00:00Z", + "decisionDate": "2025-04-10T21:10:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "motie-woonlasten-2025", + "decisionType": "motion", + "title": "Motie Woonlasten verlagen", + "text": "De raad verzoekt het college de gemeentelijke woonlasten voor 2027 niet verder te verhogen dan de inflatiecorrectie en daartoe bij de Kadernota een dekkingsvoorstel voor te leggen.", + "motionType": "motion", + "proposer": "Jan de Boer", + "lifecycle": "voting", + "isPublished": "public" + } + ], + "decision-stage": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-stage" + }, + "slug": "stage-begroting-2027-1-prep", + "sequence": 1, + "stageType": "preparatory", + "status": "decided", + "outcome": "adopted", + "decidedAt": "2026-03-02T14:00:00Z", + "method": "manual", + "decisionMakerType": "body", + "label": "Voorbereiding & vaststelling concept", + "note": "Concept vastgesteld door het directieteam. Doorgestuurd naar de commissie.", + "decision": "besluit-begroting-2027", + "assignedBody": "directieteam-gemeente-utrecht" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-stage" + }, + "slug": "stage-begroting-2027-2-adv", + "sequence": 2, + "stageType": "advisory", + "status": "decided", + "outcome": "advised", + "decidedAt": "2026-03-20T17:30:00Z", + "method": "advice", + "decisionMakerType": "person", + "label": "Advies raadscommissie", + "note": "Commissie adviseert de raad de begroting ongewijzigd vast te stellen.", + "decision": "besluit-begroting-2027", + "assignedPerson": "femke-halsema" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-stage" + }, + "slug": "stage-begroting-2027-3-dec", + "sequence": 3, + "stageType": "decisive", + "status": "decided", + "outcome": "adopted", + "decidedAt": "2026-04-15T21:30:00Z", + "method": "vote", + "decisionMakerType": "body", + "label": "Besluit gemeenteraad", + "decision": "besluit-begroting-2027", + "assignedBody": "gemeenteraad-amsterdam", + "votingRound": "stemming-begroting-2027-gemeenteraad" + } + ], + "decision-template": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-template" + }, + "slug": "corporate-board", + "name": "Corporate Board (BV)", + "description": "Decision process for the management board of a Dutch private limited company (BV).", + "context": "corporate", + "builtIn": true, + "initialState": "draft", + "stateMachine": { + "states": [ + { + "name": "draft" + }, + { + "name": "proposed" + }, + { + "name": "deliberating" + }, + { + "name": "voting" + }, + { + "name": "decided" + }, + { + "name": "enacted" + }, + { + "name": "archived" + } + ], + "transitions": [ + { + "name": "propose", + "from": "draft", + "to": "proposed" + }, + { + "name": "deliberate", + "from": "proposed", + "to": "deliberating" + }, + { + "name": "openVoting", + "from": "deliberating", + "to": "voting", + "chairOnly": true, + "guards": [ + "quorum_met" + ] + }, + { + "name": "decide", + "from": "voting", + "to": "decided" + }, + { + "name": "enact", + "from": "decided", + "to": "enacted" + }, + { + "name": "archive", + "from": "enacted", + "to": "archived" + } + ] + }, + "votingRule": { + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "tieBreakRule": "chair-decides" + }, + "quorumRequired": true, + "quorumRule": "Quorum per the articles of association", + "allowDecideWithoutVote": false, + "checklist": [] + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-template" + }, + "slug": "municipal-council", + "name": "Municipal Council", + "description": "Legislative decision process for a municipal council (gemeenteraad), Gemeentewet.", + "context": "legislative", + "builtIn": true, + "initialState": "draft", + "stateMachine": { + "states": [ + { + "name": "draft" + }, + { + "name": "proposed" + }, + { + "name": "deliberating" + }, + { + "name": "voting" + }, + { + "name": "decided" + }, + { + "name": "enacted" + }, + { + "name": "archived" + } + ], + "transitions": [ + { + "name": "propose", + "from": "draft", + "to": "proposed" + }, + { + "name": "deliberate", + "from": "proposed", + "to": "deliberating" + }, + { + "name": "openVoting", + "from": "deliberating", + "to": "voting", + "chairOnly": true, + "guards": [ + "quorum_met", + "all_amendments_resolved" + ] + }, + { + "name": "decide", + "from": "voting", + "to": "decided", + "chairOnly": true + }, + { + "name": "enact", + "from": "decided", + "to": "enacted" + }, + { + "name": "archive", + "from": "enacted", + "to": "archived" + } + ] + }, + "votingRule": { + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "tieBreakRule": "rejected" + }, + "quorumRequired": true, + "quorumRule": "More than half of the seats occupied (Gemeentewet art. 20)", + "allowDecideWithoutVote": false, + "checklist": [] + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-template" + }, + "slug": "municipal-council-urgent", + "name": "Municipal Council (urgency-enabled)", + "description": "Municipal council (gemeenteraad) process template with the urgent-decision procedure enabled: college spoedbesluit routed to a mandatory ratification stage at the next regular raadsvergadering.", + "context": "legislative", + "builtIn": false, + "initialState": "draft", + "stateMachine": { + "states": [ + { + "name": "draft" + }, + { + "name": "proposed" + }, + { + "name": "deliberating" + }, + { + "name": "voting" + }, + { + "name": "decided" + }, + { + "name": "enacted" + }, + { + "name": "archived" + } + ], + "transitions": [ + { + "name": "propose", + "from": "draft", + "to": "proposed" + }, + { + "name": "deliberate", + "from": "proposed", + "to": "deliberating" + }, + { + "name": "openVoting", + "from": "deliberating", + "to": "voting", + "chairOnly": true, + "guards": [ + "quorum_met", + "all_amendments_resolved" + ] + }, + { + "name": "decide", + "from": "voting", + "to": "decided", + "chairOnly": true + }, + { + "name": "enact", + "from": "decided", + "to": "enacted" + }, + { + "name": "archive", + "from": "enacted", + "to": "archived" + } + ] + }, + "votingRule": { + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "tieBreakRule": "rejected" + }, + "quorumRequired": true, + "quorumRule": "More than half of the seats occupied (Gemeentewet art. 20)", + "allowDecideWithoutVote": false, + "urgencyPolicy": { + "allowedTriggerRoles": [ + "chair" + ], + "minimumNoticeFloorHours": 24, + "responseDeadlineHours": { + "min": 12, + "max": 96 + }, + "ratificationRequired": true, + "ratifyingBody": "gemeenteraad-amsterdam" + }, + "checklist": [] + } + ], + "engagement-record": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "engagement-record" + }, + "slug": "engagement-raadsvergadering-fatima", + "meeting": "raadsvergadering-2025-01-15", + "participant": "fatima-el-idrissi", + "speeches": [ + { + "duration": 300 + }, + { + "duration": 120 + } + ], + "questionsRaised": [ + { + "text": "Vraag over klimaatbeleid" + } + ], + "topicsSuggested": [ + { + "title": "Woningbouw versnellen" + } + ], + "speakingDuration": 420, + "engagementScore": 32 + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "engagement-record" + }, + "slug": "engagement-raadsvergadering-jan-de-boer", + "meeting": "raadsvergadering-2025-01-15", + "participant": "jan-de-boer", + "speeches": [ + { + "duration": 180 + } + ], + "questionsRaised": [ + { + "text": "Vraag over begroting" + } + ], + "topicsSuggested": [], + "speakingDuration": 180, + "engagementScore": 15 + } + ], + "geheimhouding": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "geheimhouding" + }, + "slug": "geheimhouding-besluit-personeel", + "scope": "decision", + "targetDecision": "00000000-0000-0000-0000-000000000000", + "ground": "grond-woo-persoonlijke-levenssfeer", + "imposedBy": "body", + "imposedByBody": "gemeenteraad-amsterdam", + "imposedAt": "2026-01-19T09:00:00Z", + "lifecycle": "dissolved", + "dissolutionDecision": "00000000-0000-0000-0000-000000000000", + "liftingDate": "2026-06-25", + "liftingConditions": "openbaar na afronding onderhandelingen" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "geheimhouding" + }, + "slug": "geheimhouding-commissiestuk-vastgoed", + "scope": "item", + "targetAgendaItem": "00000000-0000-0000-0000-000000000000", + "ground": "grond-commissiestukken", + "imposedBy": "chair", + "imposedByBody": "gemeenteraad-amsterdam", + "imposedAt": "2026-03-02T13:30:00Z", + "lifecycle": "imposed", + "ratificationDeadline": "2026-04-01" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "geheimhouding" + }, + "slug": "geheimhouding-raadsnota-grondexploitatie", + "scope": "document", + "targetDocument": "00000000-0000-0000-0000-000000000000", + "ground": "grond-raadsstukken", + "imposedBy": "executive-board", + "imposedByBody": "gemeenteraad-amsterdam", + "imposedAt": "2026-06-08T10:00:00Z", + "lifecycle": "imposed", + "ratificationDeadline": "2026-09-30" + } + ], + "geheimhouding-grond": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "geheimhouding-grond" + }, + "slug": "grond-collegestukken", + "name": "Geheimhouding collegestukken", + "citation": "Gemeentewet art. 87-89", + "legacyCitation": "voorheen art. 55", + "category": "municipalities-act", + "requiresRatification": false, + "description": "Geheimhouding opgelegd door of namens het college op collegestukken. Post-2023 Gemeentewet art. 87-89; voorheen art. 55.", + "builtIn": true, + "active": true + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "geheimhouding-grond" + }, + "slug": "grond-commissiestukken", + "name": "Geheimhouding commissiestukken", + "citation": "Gemeentewet art. 87-89", + "legacyCitation": "voorheen art. 86", + "category": "municipalities-act", + "requiresRatification": true, + "description": "Geheimhouding opgelegd in een raadscommissie op commissiestukken; bekrachtiging door de raad vereist. Post-2023 Gemeentewet art. 87-89; voorheen art. 86.", + "builtIn": true, + "active": true + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "geheimhouding-grond" + }, + "slug": "grond-raadsstukken", + "name": "Geheimhouding raadsstukken", + "citation": "Gemeentewet art. 87-89", + "legacyCitation": "voorheen art. 25", + "category": "municipalities-act", + "requiresRatification": true, + "description": "Geheimhouding opgelegd op stukken bestemd voor of behandeld door de raad. Onder het regime van de Wet bevorderen integriteit en functioneren decentraal bestuur (2023) geldt Gemeentewet art. 87-89; voorheen art. 25.", + "builtIn": true, + "active": true + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "geheimhouding-grond" + }, + "slug": "grond-woo-bedrijfsgegevens", + "name": "Vertrouwelijk verstrekte bedrijfs- en fabricagegegevens", + "citation": "Woo art. 5.1 lid 1", + "legacyCitation": null, + "category": "woo-absolute", + "requiresRatification": false, + "description": "Absolute uitzonderingsgrond (Woo art. 5.1 lid 1): vertrouwelijk aan de overheid meegedeelde bedrijfs- en fabricagegegevens.", + "builtIn": true, + "active": true + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "geheimhouding-grond" + }, + "slug": "grond-woo-financieel-economisch", + "name": "Financiële en economische belangen van het bestuursorgaan", + "citation": "Woo art. 5.1 lid 2", + "legacyCitation": null, + "category": "woo-relative", + "requiresRatification": false, + "description": "Relatieve uitzonderingsgrond (Woo art. 5.1 lid 2): financiële en economische belangen van het bestuursorgaan.", + "builtIn": true, + "active": true + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "geheimhouding-grond" + }, + "slug": "grond-woo-kroon-veiligheid", + "name": "Eenheid van de Kroon / veiligheid van de Staat", + "citation": "Woo art. 5.1 lid 1", + "legacyCitation": null, + "category": "woo-absolute", + "requiresRatification": false, + "description": "Absolute uitzonderingsgrond (Woo art. 5.1 lid 1): eenheid van de Kroon en veiligheid van de Staat.", + "builtIn": true, + "active": true + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "geheimhouding-grond" + }, + "slug": "grond-woo-persoonlijke-levenssfeer", + "name": "Eerbiediging van de persoonlijke levenssfeer", + "citation": "Woo art. 5.1 lid 2", + "legacyCitation": null, + "category": "woo-relative", + "requiresRatification": false, + "description": "Relatieve uitzonderingsgrond (Woo art. 5.1 lid 2): eerbiediging van de persoonlijke levenssfeer.", + "builtIn": true, + "active": true + } + ], + "geschenk": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "geschenk" + }, + "slug": "gs-boek-delegatie", + "recipient": "marie-janssen", + "governanceBody": "gemeenteraad-amsterdam", + "type": "gift", + "giver": "Delegatie gemeente Aken", + "description": "Fotoboek stedenband", + "estimatedValue": 20, + "receivedOn": "2026-01-20", + "decision": "accepted", + "declaredAt": "2026-01-21", + "publicationDate": "2026-01-25T09:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "geschenk" + }, + "slug": "gs-diner-projectontwikkelaar", + "recipient": "marie-janssen", + "governanceBody": "gemeenteraad-amsterdam", + "type": "invitation", + "giver": "Projectontwikkelaar BV", + "description": "Diner nieuwjaarsreceptie", + "estimatedValue": 95, + "receivedOn": "2026-01-08", + "decision": "refused", + "notes": "Boven het drempelbedrag; uitnodiging geweigerd conform gedragscode.", + "declaredAt": "2026-01-09", + "publicationDate": "2026-01-15T09:00:00Z" + } + ], + "goal": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "goal" + }, + "slug": "goal-amsterdam-klimaatneutraal-2050", + "title": "Amsterdam klimaatneutraal", + "description": "Netto CO2-uitstoot van de gemeentelijke organisatie naar nul in 2050, conform het raadsbesluit klimaatakkoord.", + "horizon": "multi-year", + "body": "gemeenteraad-amsterdam", + "owner": "femke-halsema", + "startDate": "2026-01-01", + "deadline": "2050-01-01", + "status": "active", + "targetValue": 100, + "currentValue": 42, + "unit": "% CO2-reductie behaald" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "goal" + }, + "slug": "goal-amsterdam-parkeerbeleid-kwartaal", + "title": "Herzien parkeerbeleid vastgesteld", + "description": "Vaststellen van het herziene parkeerbeleid binnenstad (koppeling met de termijnagenda).", + "horizon": "quarterly", + "body": "gemeenteraad-amsterdam", + "owner": "00000000-0000-0000-0000-000000000000", + "startDate": "2026-04-01", + "deadline": "2026-09-30", + "status": "at-risk", + "parentGoal": "goal-amsterdam-klimaatneutraal-2050" + } + ], + "governance-body": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "adviesraad-sociaal-domein", + "name": "Adviesraad Sociaal Domein", + "bodyType": "advisory-body", + "domain": "municipality", + "workflowTemplate": "legislative" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "auditcommissie-provincie-nh", + "name": "Auditcommissie Provincie Noord-Holland", + "bodyType": "legislative", + "domain": "province", + "votingDefault": "for-against-abstain" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "bestuur-noz-organisatie", + "name": "Bestuur NOZ organisatie", + "bodyType": "shared-body", + "domain": "municipal", + "workflowTemplate": "legislative" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "bezwaaradviescommissie-amsterdam", + "name": "Bezwaaradviescommissie Amsterdam", + "bodyType": "advisory-body", + "domain": "municipality", + "statutoryBasis": "Awb 7:13", + "jurisdiction": "Gemeente Amsterdam — algemene bezwaren", + "quorum": 3, + "quorumRule": "majority", + "active": true, + "termStart": "2024-01-01T00:00:00Z", + "termEnd": "2028-01-01T00:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "d66-fractie-amsterdam", + "name": "D66-fractie", + "bodyType": "faction", + "domain": "municipality", + "parentBody": "gemeenteraad-amsterdam", + "votingDefault": "for-against-abstain" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "directieteam-gemeente-utrecht", + "name": "Directieteam Gemeente Utrecht", + "bodyType": "operational", + "domain": "municipality", + "votingDefault": "show-of-hands" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "gemeenteraad-amsterdam", + "name": "Gemeenteraad Amsterdam", + "bodyType": "legislative", + "domain": "municipality", + "votingDefault": "for-against-abstain", + "termStart": "2022-03-16T00:00:00Z", + "termEnd": "2026-03-15T00:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "gemeenteraad-noorderbrug", + "name": "Gemeenteraad Noorderbrug", + "bodyType": "legislative", + "domain": "municipal", + "workflowTemplate": "legislative" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "gemeenteraad-oostwoud", + "name": "Gemeenteraad Oostwoud", + "bodyType": "legislative", + "domain": "municipal", + "workflowTemplate": "legislative" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "gemeenteraad-zuidermeer", + "name": "Gemeenteraad Zuidermeer", + "bodyType": "legislative", + "domain": "municipal", + "workflowTemplate": "legislative" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "groenlinks-fractie-amsterdam", + "name": "GroenLinks-fractie", + "bodyType": "faction", + "domain": "municipality", + "parentBody": "gemeenteraad-amsterdam", + "votingDefault": "for-against-abstain" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "jongerenraad", + "name": "Jongerenraad", + "bodyType": "advisory-body", + "domain": "municipality", + "workflowTemplate": "citizen" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "rvc-waterschap-amstel", + "name": "Raad van Commissarissen Waterschap Amstel, Gooi en Vecht", + "bodyType": "corporate-board", + "domain": "water-authority", + "votingDefault": "for-against-abstain", + "termStart": "2023-01-01T00:00:00Z", + "termEnd": "2026-12-31T00:00:00Z" + } + ], + "governing-document": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governing-document" + }, + "slug": "reglement-van-orde-raad-amsterdam", + "type": "rules-of-procedure", + "citationTitle": "Reglement van orde gemeenteraad Amsterdam", + "description": "Reglement van orde van de gemeenteraad (Gemeentewet art. 16), vastgesteld bij raadsbesluit.", + "governingBody": "gemeenteraad-amsterdam", + "isPublic": false, + "status": "in-force" + } + ], + "governing-document-versie": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governing-document-versie" + }, + "slug": "rvo-amsterdam-v1", + "document": "reglement-van-orde-raad-amsterdam", + "versionNumber": 1, + "determinedBy": "besluit-vaststelling-rvo-amsterdam", + "effectiveDate": "2023-03-01", + "notes": "Vaststelling van het reglement van orde door de gemeenteraad.", + "status": "in-effect" + } + ], + "ingekomen-stuk": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "ingekomen-stuk" + }, + "slug": "brief-verkeersveiligheid-schoolzone", + "title": "Brief inzake verkeersveiligheid schoolzone Lindelaan", + "sender": "J. Jansen", + "senderType": "natural-person", + "receivedAt": "2026-01-12", + "category": "letter-resident", + "routingAdvice": "referred-to-executive-board-for-disposal", + "listAgendaItem": "lijst-ingekomen-stukken-2025-01-15", + "directedTo": "gemeenteraad-amsterdam", + "lifecycle": "routing-determined" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "ingekomen-stuk" + }, + "slug": "collegestuk-jaarverantwoording", + "title": "Jaarverantwoording kinderopvang 2025", + "sender": "College van B&W", + "senderType": "governingBody", + "receivedAt": "2026-01-18", + "category": "executive-board-paper", + "routingAdvice": "noted-for-information", + "listAgendaItem": "lijst-ingekomen-stukken-2025-01-15", + "directedTo": "gemeenteraad-amsterdam", + "lifecycle": "routing-determined" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "ingekomen-stuk" + }, + "slug": "petitie-behoud-zwembad", + "title": "Petitie behoud zwembad De Plons (1.243 ondertekenaars)", + "sender": "Actiecomité De Plons", + "senderType": "organisation", + "receivedAt": "2026-01-15", + "category": "petition", + "routingAdvice": "include-with-agenda-item", + "targetAgendaItem": "begroting-2026-bespreking", + "listAgendaItem": "lijst-ingekomen-stukken-2025-01-15", + "directedTo": "gemeenteraad-amsterdam", + "lifecycle": "agendised" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "ingekomen-stuk" + }, + "slug": "uitnodiging-veiligheidsregio", + "title": "Uitnodiging werkbezoek Veiligheidsregio", + "sender": "Veiligheidsregio Midden-Nederland", + "senderType": "governingBody", + "receivedAt": "2026-01-19", + "category": "invitation", + "routingAdvice": "noted-for-information", + "directedTo": "gemeenteraad-amsterdam", + "lifecycle": "registered" + } + ], + "integriteitsbeleid": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "integriteitsbeleid" + }, + "slug": "beleid-gemeenteraad", + "governanceBody": "gemeenteraad-amsterdam", + "ancillaryPositionDisclosureDefault": "public", + "giftThresholdAmount": 50, + "giftsPublic": true, + "integrityNotificationGroup": "decidesk-burgemeester" + } + ], + "interpellatieverzoek": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "interpellatieverzoek" + }, + "slug": "int-jaarrekening-grondbedrijf", + "requestNumber": "INT-2026-002", + "subject": "Tekorten jaarrekening grondbedrijf", + "questions": "1. Waarom is de raad niet geïnformeerd over de tekorten in het grondbedrijf? 2. Welke gevolgen heeft dit voor de meerjarenbegroting?", + "rationale": "De omvang van de tekorten en het uitblijven van informatie aan de raad vragen om een interpellatie.", + "requester": "00000000-0000-0000-0000-000000000000", + "politicalGroup": "00000000-0000-0000-0000-000000000000", + "portfolioHolder": "00000000-0000-0000-0000-000000000000", + "governanceBody": "gemeenteraad-amsterdam", + "steunbetuigingen": [ + "00000000-0000-0000-0000-000000000000", + "00000000-0000-0000-0000-000000000000" + ], + "lifecycle": "submitted" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "interpellatieverzoek" + }, + "slug": "int-subsidie-cultuurhuis", + "requestNumber": "INT-2026-003", + "subject": "Subsidieverlening cultuurhuis", + "questions": "1. Op welke grond is de subsidie aan het cultuurhuis verhoogd? 2. Voldoet de verhoging aan het geldende subsidiekader?", + "rationale": "De onderbouwing van de subsidieverhoging is voor de raad onvoldoende inzichtelijk.", + "requester": "00000000-0000-0000-0000-000000000000", + "politicalGroup": "00000000-0000-0000-0000-000000000000", + "portfolioHolder": "00000000-0000-0000-0000-000000000000", + "governanceBody": "gemeenteraad-amsterdam", + "steunbetuigingen": [ + "00000000-0000-0000-0000-000000000000", + "00000000-0000-0000-0000-000000000000", + "00000000-0000-0000-0000-000000000000", + "00000000-0000-0000-0000-000000000000", + "00000000-0000-0000-0000-000000000000" + ], + "lifecycle": "agendised", + "councilResolutionDate": "2026-06-30", + "behandeldIn": "raadsvergadering-2025-01-15", + "agendaItem": "interpellatie-cultuurhuis-2025-01-15" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "interpellatieverzoek" + }, + "slug": "int-veiligheid-stationsgebied", + "requestNumber": "INT-2026-001", + "subject": "Veiligheid stationsgebied", + "questions": "1. Sinds wanneer was het college bekend met de toename van incidenten in het stationsgebied? 2. Welke maatregelen zijn getroffen en waarom is de raad hierover niet eerder geïnformeerd?", + "rationale": "De aanhoudende onveiligheid in het stationsgebied rechtvaardigt een interpellatiedebat buiten de orde van de dag.", + "requester": "00000000-0000-0000-0000-000000000000", + "politicalGroup": "00000000-0000-0000-0000-000000000000", + "portfolioHolder": "00000000-0000-0000-0000-000000000000", + "governanceBody": "gemeenteraad-amsterdam", + "steunbetuigingen": [ + "00000000-0000-0000-0000-000000000000", + "00000000-0000-0000-0000-000000000000", + "00000000-0000-0000-0000-000000000000", + "00000000-0000-0000-0000-000000000000" + ], + "lifecycle": "handled", + "councilResolutionDate": "2026-05-12", + "behandeldIn": "raadsvergadering-2025-01-15", + "agendaItem": "interpellatie-stationsgebied-2025", + "handlingMinutes": "Interpellatiedebat gevoerd; wethouder zegt extern onderzoek toe naar de veiligheidssituatie en informeert de raad per raadsbrief voor het zomerreces." + } + ], + "meeting": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "meeting" + }, + "slug": "raadsvergadering-2025-01-15", + "title": "Raadsvergadering 15 januari 2025", + "meetingType": "regular", + "scheduledDate": "2025-01-15T19:30:00Z", + "endDate": "2025-01-15T23:00:00Z", + "location": "Stadhuis Amsterdam, Raadzaal", + "meetingMode": "hybrid", + "lifecycle": "closed" + } + ], + "member-consultation": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "member-consultation" + }, + "slug": "raadpleging-fractie-parkeervisie", + "question": "Steunt de fractie het raadsvoorstel Parkeervisie 2026–2030 in de huidige vorm?", + "description": "Niet-bindende peiling ter voorbereiding op de raadsvergadering van 12 maart.", + "responseType": "single-choice", + "choiceOptions": [ + "Voor", + "Tegen", + "Voor, mits aangepast" + ], + "audienceType": "politicalGroup", + "audienceBody": "gemeenteraad-amsterdam", + "audienceParty": "Groen Voorbeeldingen", + "agendaItem": "begroting-2026-bespreking", + "opensAt": "2026-02-20T09:00:00Z", + "closesAt": "2026-03-10T17:00:00Z", + "anonymousResponses": false, + "lifecycle": "open" + } + ], + "member-consultation-response": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "member-consultation-response" + }, + "slug": "respons-parkeervisie-lid-1", + "consultation": "raadpleging-fractie-parkeervisie", + "respondentId": "jvandenberg", + "choices": [ + "Voor, mits aangepast" + ], + "openText": "Mits de parkeernorm voor de binnenstad wordt verlaagd.", + "submittedAt": "2026-02-21T10:15:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "member-consultation-response" + }, + "slug": "respons-parkeervisie-lid-2", + "consultation": "raadpleging-fractie-parkeervisie", + "respondentId": "mjansen", + "choices": [ + "Tegen" + ], + "submittedAt": "2026-02-22T08:40:00Z" + } + ], + "membership": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "membership" + }, + "slug": "lidmaatschap-terpstra-noz", + "role": "member", + "person": "persoon-a-terpstra", + "governanceBody": "bestuur-noz-organisatie", + "onBehalfOf": "gemeenteraad-zuidermeer", + "votingWeight": 1, + "startDate": "2018-04-01" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "membership" + }, + "slug": "lidmaatschap-van-dam-noz", + "role": "chair", + "person": "persoon-w-van-dam", + "governanceBody": "bestuur-noz-organisatie", + "onBehalfOf": "gemeenteraad-noorderbrug", + "votingWeight": 2, + "startDate": "2018-04-01" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "membership" + }, + "slug": "m-femke-amsterdam", + "role": "chair", + "label": "Voorzitter raad", + "party": "GroenLinks", + "votingWeight": 1, + "startDate": "2018-05-30T00:00:00Z", + "person": "femke-halsema", + "governanceBody": "gemeenteraad-amsterdam", + "post": "post-voorzitter-amsterdam" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "membership" + }, + "slug": "m-jan-amstel", + "role": "secretary", + "label": "Raadsgriffier", + "votingWeight": 0, + "startDate": "2021-01-15T00:00:00Z", + "person": "jan-de-vries", + "governanceBody": "rvc-waterschap-amstel", + "post": "post-griffier-amsterdam" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "membership" + }, + "slug": "m-marie-amsterdam", + "role": "member", + "label": "Raadslid", + "party": "D66", + "votingWeight": 1, + "startDate": "2022-03-16T00:00:00Z", + "person": "marie-janssen", + "governanceBody": "gemeenteraad-amsterdam" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "membership" + }, + "slug": "m-marie-groenlinks-fractie", + "role": "member", + "label": "Fractielid", + "party": "GroenLinks", + "votingWeight": 1, + "startDate": "2022-03-16T00:00:00Z", + "person": "marie-janssen", + "governanceBody": "groenlinks-fractie-amsterdam" + } + ], + "minutes": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "minutes" + }, + "slug": "notulen-ab-waterschap-2025-02-13", + "title": "Notulen AB Waterschap Aa en Maas 13 februari 2025", + "lifecycle": "draft", + "version": 1 + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "minutes" + }, + "slug": "notulen-ab-waterschap-2025-04-10", + "title": "Notulen Vergadering Algemeen Bestuur Waterschap Aa en Maas 10 april 2025", + "lifecycle": "review", + "content": "Concept-verslag ter vaststelling. De vergadering van het Algemeen Bestuur wordt geopend door de dijkgraaf om 14:00 uur.", + "version": 1 + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "minutes" + }, + "slug": "notulen-commissie-ruimte-2025-03-04", + "title": "Notulen Commissievergadering Ruimte & Wonen 4 maart 2025", + "lifecycle": "signed", + "content": "De commissievergadering Ruimte & Wonen wordt geopend...", + "approvedAt": "2025-04-01T10:00:00Z", + "signedBy": [ + "Henk Bakker" + ], + "version": 1 + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "minutes" + }, + "slug": "notulen-commissie-wonen-2025-04-01", + "title": "Notulen Commissievergadering Wonen & Ruimte 1 april 2025", + "lifecycle": "signed", + "content": "Aanvang: 19:00 uur. Voorzitter: Henk Bakker. Commissieleden aanwezig: 7 van 9. Agendapunt 2 — bestemmingsplan Groningen-Noord: de commissie adviseert de raad het plan ongewijzigd vast te stellen.", + "approvedAt": "2025-04-15T10:00:00Z", + "signedBy": [ + "Henk Bakker" + ], + "version": 1 + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "minutes" + }, + "slug": "notulen-raad-2025-03-20", + "title": "Notulen Gemeenteraadsvergadering 20 maart 2025", + "lifecycle": "published", + "content": "De vergadering wordt geopend door de voorzitter om 19:30 uur. Aanwezig: 33 van 37 raadsleden. Punt 5 — Woningbouwplan Oost 2025-2030: na bespreking wordt het plan aangenomen met 30 stemmen voor en 3 tegen.", + "approvedAt": "2025-04-10T19:45:00Z", + "signedBy": [ + "Roos de Vries", + "Jan Bakker" + ], + "version": 2 + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "minutes" + }, + "slug": "notulen-raad-2025-04-10", + "title": "Notulen Raadsvergadering 10 april 2025", + "lifecycle": "approved", + "content": "De vergadering wordt geopend door de voorzitter om 19:30 uur...", + "approvedAt": "2025-05-08T19:45:00Z", + "signedBy": [ + "Roos de Vries", + "Jan Bakker" + ], + "version": 2 + } + ], + "mondelinge-vraag": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "mondelinge-vraag" + }, + "slug": "mv-opvang-statushouders", + "questionNumber": "MV-2026-004", + "subject": "Opvangcapaciteit statushouders Q3", + "rationale": "Graag inzicht in de opvangcapaciteit voor statushouders in het derde kwartaal en de gevolgen voor de taakstelling.", + "submitter": "00000000-0000-0000-0000-000000000000", + "politicalGroup": "00000000-0000-0000-0000-000000000000", + "portfolioHolder": "00000000-0000-0000-0000-000000000000", + "governanceBody": "gemeenteraad-amsterdam", + "targetMeeting": "raadsvergadering-2025-01-15", + "lifecycle": "rejected", + "rejectionReason": "Betreft een individuele casus, geen algemeen belang" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "mondelinge-vraag" + }, + "slug": "mv-sluiting-zwembad", + "questionNumber": "MV-2026-003", + "subject": "Voorgenomen sluiting zwembad De Plons", + "rationale": "In de media wordt gesproken over een voorgenomen sluiting van zwembad De Plons. Klopt dit en is de raad hierover tijdig geïnformeerd?", + "submitter": "00000000-0000-0000-0000-000000000000", + "politicalGroup": "00000000-0000-0000-0000-000000000000", + "portfolioHolder": "00000000-0000-0000-0000-000000000000", + "governanceBody": "gemeenteraad-amsterdam", + "targetMeeting": "raadsvergadering-2025-01-15", + "lifecycle": "submitted" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "mondelinge-vraag" + }, + "slug": "mv-verkeersveiligheid-lindelaan", + "questionNumber": "MV-2026-002", + "subject": "Verkeersveiligheid schoolzone Lindelaan", + "rationale": "Ouders melden onveilige situaties tijdens de spits bij de schoolzone Lindelaan. Welke korte-termijnmaatregelen ziet het college?", + "submitter": "00000000-0000-0000-0000-000000000000", + "politicalGroup": "00000000-0000-0000-0000-000000000000", + "portfolioHolder": "00000000-0000-0000-0000-000000000000", + "governanceBody": "gemeenteraad-amsterdam", + "targetMeeting": "raadsvergadering-2025-01-15", + "questionHourAgendaItem": "vragenuur-2025-01-15", + "sortOrder": 2, + "lifecycle": "scheduled" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "mondelinge-vraag" + }, + "slug": "mv-wachtlijsten-jeugdzorg", + "questionNumber": "MV-2026-001", + "subject": "Wachtlijsten jeugdzorg na aanbesteding", + "rationale": "Na de recente aanbesteding jeugdhulp bereiken de fractie signalen van oplopende wachttijden. Graag een toelichting van de portefeuillehouder op de actuele stand en de te nemen maatregelen.", + "submitter": "00000000-0000-0000-0000-000000000000", + "politicalGroup": "00000000-0000-0000-0000-000000000000", + "portfolioHolder": "00000000-0000-0000-0000-000000000000", + "governanceBody": "gemeenteraad-amsterdam", + "targetMeeting": "raadsvergadering-2025-01-15", + "questionHourAgendaItem": "vragenuur-2025-01-15", + "sortOrder": 1, + "lifecycle": "answered", + "answerSummary": "Wethouder erkent oplopende wachttijden; raadsbrief met plan van aanpak toegezegd vóór 1 maart.", + "answeredBy": "00000000-0000-0000-0000-000000000000", + "followUpCommitment": "toezegging-raadsbrief-jeugdzorg", + "sourceWrittenQuestion": "00000000-0000-0000-0000-000000000000" + } + ], + "nevenfunctie": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "nevenfunctie" + }, + "slug": "nf-adviseur-beeindigd", + "person": "jan-de-vries", + "governanceBody": "gemeenteraad-amsterdam", + "organisation": "Adviesbureau De Kern", + "role": "adviseur", + "remunerated": true, + "qualitateQua": false, + "startDate": "2021-06-01", + "endDate": "2025-12-31", + "declaredAt": "2021-06-05", + "lifecycle": "ended", + "publicationDate": "2021-06-10T09:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "nevenfunctie" + }, + "slug": "nf-bestuurslid-welzijn", + "person": "marie-janssen", + "governanceBody": "gemeenteraad-amsterdam", + "organisation": "Stichting Welzijn Noord", + "role": "bestuurslid", + "remunerated": false, + "hoursIndication": "4 uur/week", + "qualitateQua": false, + "startDate": "2024-03-01", + "declaredAt": "2024-03-05", + "reviewedAt": "2025-05-15", + "lifecycle": "public", + "publicationDate": "2024-03-10T09:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "nevenfunctie" + }, + "slug": "nf-docent-hogeschool", + "person": "marie-janssen", + "governanceBody": "gemeenteraad-amsterdam", + "organisation": "Hogeschool Amsterdam", + "role": "docent bestuurskunde", + "remunerated": true, + "hoursIndication": "8 uur/week", + "qualitateQua": false, + "startDate": "2025-09-01", + "declaredAt": "2025-09-03", + "lifecycle": "reported" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "nevenfunctie" + }, + "slug": "nf-gr-afvalschap-qq", + "person": "jan-de-vries", + "governanceBody": "gemeenteraad-amsterdam", + "organisation": "Gemeenschappelijke Regeling Afvalschap", + "role": "lid algemeen bestuur", + "remunerated": false, + "qualitateQua": true, + "startDate": "2023-05-01", + "declaredAt": "2023-05-08", + "reviewedAt": "2026-06-15", + "lifecycle": "public", + "publicationDate": "2023-05-12T09:00:00Z" + } + ], + "offboarding-traject": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "offboarding-traject" + }, + "slug": "offboarding-jan-de-vries-raadswisseling", + "person": "jan-de-vries", + "body": "gemeenteraad-amsterdam", + "membership": "00000000-0000-0000-0000-000000000000", + "trigger": "council-turnover-batch", + "batch": "raadswisseling-2026", + "endDate": "2026-03-29", + "endReason": "end-of-council-membership", + "lifecycle": "in-execution", + "steps": [ + { + "stepType": "end-membership", + "title": "Lidmaatschap einddateren", + "status": "completed", + "mandatory": true, + "completedAt": "2026-03-29T18:00:00Z", + "completedBy": "griffier", + "note": "endDate = eindeDatum (person-and-membership)." + }, + { + "stepType": "revoke-groups", + "title": "Groepen en RBAC-scope intrekken", + "status": "open", + "mandatory": true, + "dueDate": "2026-03-30", + "note": "Fail-closed en altijd verplicht: traject kan niet naar afgerond zolang deze stap open is (REQ-MOB-008)." + }, + { + "stepType": "personal-data-note", + "title": "Persoonsgegevens-notitie (AVG)", + "status": "open", + "mandatory": true, + "dueDate": "2026-04-05", + "note": "Verwijst naar de eigen-annotaties-export van document-annotations; geen eigen export." + }, + { + "stepType": "exit-confirmation", + "title": "Exit bevestigen", + "status": "open", + "mandatory": true, + "dueDate": "2026-04-05" + } + ] + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "offboarding-traject" + }, + "slug": "offboarding-janneke-de-bruin-individueel", + "person": "janneke-de-bruin", + "body": "gemeenteraad-amsterdam", + "membership": "00000000-0000-0000-0000-000000000000", + "trigger": "individual", + "endDate": "2026-01-15", + "endReason": "resignation", + "lifecycle": "completed", + "exitConfirmedBy": "griffier", + "exitConfirmedOn": "2026-01-20T14:00:00Z", + "steps": [ + { + "stepType": "end-membership", + "title": "Lidmaatschap einddateren", + "status": "completed", + "mandatory": true, + "completedAt": "2026-01-15T17:00:00Z", + "completedBy": "griffier" + }, + { + "stepType": "revoke-groups", + "title": "Groepen en RBAC-scope intrekken", + "status": "completed", + "mandatory": true, + "completedAt": "2026-01-15T17:30:00Z", + "completedBy": "griffier", + "note": "Body-role-gemapte groepen verwijderd; niet-gerelateerde groepen ongemoeid." + }, + { + "stepType": "personal-data-note", + "title": "Persoonsgegevens-notitie (AVG)", + "status": "completed", + "mandatory": true, + "completedAt": "2026-01-18T11:00:00Z", + "completedBy": "griffier" + }, + { + "stepType": "exit-confirmation", + "title": "Exit bevestigen", + "status": "completed", + "mandatory": true, + "completedAt": "2026-01-20T14:00:00Z", + "completedBy": "griffier" + } + ] + } + ], + "onboarding-traject": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "onboarding-traject" + }, + "slug": "onboarding-jan-de-vries-opvolging", + "person": "jan-de-vries", + "targetBody": "gemeenteraad-amsterdam", + "targetRole": "member", + "trigger": "interim-succession", + "lifecycle": "started", + "steps": [ + { + "stepType": "swearing-in", + "title": "Beëdiging vastleggen", + "status": "open", + "mandatory": true, + "dueDate": "2026-08-15" + }, + { + "stepType": "account-linking", + "title": "Nextcloud-account koppelen", + "status": "open", + "mandatory": true, + "dueDate": "2026-08-15" + }, + { + "stepType": "assign-groups", + "title": "Groepen en RBAC-scope toewijzen", + "status": "open", + "mandatory": true, + "dueDate": "2026-08-20" + }, + { + "stepType": "induction-pack", + "title": "Introductiepakket bezorgen", + "status": "open", + "mandatory": false, + "dueDate": "2026-08-22" + }, + { + "stepType": "ancillary-positions-intake", + "title": "Nevenfuncties uitvragen", + "status": "open", + "mandatory": true, + "dueDate": "2026-08-22" + }, + { + "stepType": "political-group-assignment", + "title": "Fractie toewijzen", + "status": "open", + "mandatory": false, + "dueDate": "2026-08-22" + } + ] + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "onboarding-traject" + }, + "slug": "onboarding-janneke-de-bruin-nieuw-lid", + "person": "janneke-de-bruin", + "targetBody": "gemeenteraad-amsterdam", + "targetRole": "treasurer", + "trigger": "new-member", + "lifecycle": "completed", + "ncAccount": "jdebruin", + "membership": "00000000-0000-0000-0000-000000000000", + "swearingInDate": "2025-11-10", + "beëdigingsType": "oath", + "swearingInMeeting": "raadsvergadering-2025-01-15", + "steps": [ + { + "stepType": "swearing-in", + "title": "Beëdiging vastleggen", + "status": "completed", + "mandatory": true, + "completedAt": "2025-11-10T20:00:00Z", + "completedBy": "griffier", + "reference": "raadsvergadering-2025-01-15", + "note": "Eed afgelegd bij aanvang bestuurslidmaatschap (ALV-gekozen — vereniging-analoog, demonstreert het niet-gemeentelijke domein)." + }, + { + "stepType": "account-linking", + "title": "Nextcloud-account koppelen", + "status": "completed", + "mandatory": true, + "completedAt": "2025-11-11T09:00:00Z", + "completedBy": "griffier", + "reference": "jdebruin" + }, + { + "stepType": "assign-groups", + "title": "Groepen en RBAC-scope toewijzen", + "status": "completed", + "mandatory": true, + "completedAt": "2025-11-11T09:30:00Z", + "completedBy": "griffier", + "note": "Toegevoegd aan penningmeester-groep; RBAC-scope volgt via de role→scope-projectie." + }, + { + "stepType": "induction-pack", + "title": "Introductiepakket bezorgen", + "status": "completed", + "mandatory": false, + "completedAt": "2025-11-12T10:00:00Z", + "completedBy": "griffier", + "reference": "/Introductiepakket-JdeBruin" + }, + { + "stepType": "ancillary-positions-intake", + "title": "Nevenfuncties uitvragen", + "status": "skipped", + "mandatory": false, + "note": "Geen nevenfuncties opgegeven; stap overgeslagen (verplicht false)." + }, + { + "stepType": "political-group-assignment", + "title": "Fractie toewijzen", + "status": "completed", + "mandatory": false, + "completedAt": "2025-11-12T10:15:00Z", + "completedBy": "griffier" + } + ] + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "onboarding-traject" + }, + "slug": "onboarding-marie-janssen-raadswisseling", + "person": "marie-janssen", + "targetBody": "gemeenteraad-amsterdam", + "targetRole": "member", + "trigger": "council-turnover-batch", + "batch": "raadswisseling-2026", + "lifecycle": "in-execution", + "ncAccount": "mjanssen", + "membership": "00000000-0000-0000-0000-000000000000", + "swearingInDate": "2026-03-26", + "beëdigingsType": "affirmation", + "swearingInMeeting": "raadsvergadering-2025-01-15", + "steps": [ + { + "stepType": "swearing-in", + "title": "Beëdiging vastleggen", + "status": "completed", + "mandatory": true, + "completedAt": "2026-03-26T20:15:00Z", + "completedBy": "griffier", + "reference": "raadsvergadering-2025-01-15", + "note": "Belofte afgelegd tijdens de installatievergadering." + }, + { + "stepType": "account-linking", + "title": "Nextcloud-account koppelen", + "status": "completed", + "mandatory": true, + "completedAt": "2026-03-27T09:00:00Z", + "completedBy": "griffier", + "reference": "mjanssen" + }, + { + "stepType": "assign-groups", + "title": "Groepen en RBAC-scope toewijzen", + "status": "open", + "mandatory": true, + "dueDate": "2026-06-01", + "note": "Wacht op bevestiging body-role→groep-mapping (drijft de overdue-KPI en het overdue-rappel)." + }, + { + "stepType": "induction-pack", + "title": "Introductiepakket bezorgen", + "status": "open", + "mandatory": false, + "dueDate": "2026-06-15", + "note": "iPad reserveren." + }, + { + "stepType": "ancillary-positions-intake", + "title": "Nevenfuncties uitvragen", + "status": "open", + "mandatory": true, + "dueDate": "2026-06-15" + }, + { + "stepType": "political-group-assignment", + "title": "Fractie toewijzen", + "status": "open", + "mandatory": false, + "dueDate": "2026-06-15" + } + ] + } + ], + "participant": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "participant" + }, + "slug": "femke-halsema", + "displayName": "Femke Halsema", + "role": "chair", + "email": "f.halsema@amsterdam.nl", + "joinedAt": "2018-05-30T00:00:00Z", + "votingWeight": 1 + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "participant" + }, + "slug": "jan-de-vries", + "displayName": "Jan de Vries", + "role": "secretary", + "email": "j.devries@waterschap.nl", + "joinedAt": "2021-01-15T00:00:00Z", + "votingWeight": 1 + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "participant" + }, + "slug": "marie-janssen", + "displayName": "Marie Janssen", + "role": "member", + "party": "D66", + "email": "m.janssen@amsterdam.nl", + "joinedAt": "2022-03-16T00:00:00Z", + "votingWeight": 1 + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "participant" + }, + "slug": "pieter-bakker", + "displayName": "Pieter Bakker", + "role": "chair", + "email": "p.bakker@utrecht.nl", + "joinedAt": "2020-06-01T00:00:00Z", + "votingWeight": 1 + } + ], + "pc-cyclus": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "pc-cyclus" + }, + "slug": "pc-cyclus-2026-gemeenteraad", + "name": "P&C-cyclus 2026", + "year": 2026, + "governanceBody": "gemeenteraad-amsterdam", + "template": "municipal-pc-cyclus", + "stepCount": 5, + "completedStepCount": 2, + "overdueStepCount": 1 + } + ], + "person": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "person" + }, + "slug": "femke-halsema", + "name": "Femke Halsema", + "givenName": "Femke", + "familyName": "Halsema", + "gender": "female", + "email": "f.halsema@amsterdam.nl", + "biography": "Burgemeester van Amsterdam, voorzitter van de gemeenteraad." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "person" + }, + "slug": "jan-de-vries", + "name": "Jan de Vries", + "givenName": "Jan", + "familyName": "de Vries", + "gender": "male", + "email": "j.devries@waterschap.nl", + "biography": "Secretaris / griffier." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "person" + }, + "slug": "janneke-de-bruin", + "name": "Janneke de Bruin", + "givenName": "Janneke", + "familyName": "de Bruin", + "gender": "female", + "email": "j.debruin@acme.example", + "biography": "Voorzitter Raad van Commissarissen.", + "nationality": "NL" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "person" + }, + "slug": "marie-janssen", + "name": "Marie Janssen", + "givenName": "Marie", + "familyName": "Janssen", + "gender": "female", + "email": "m.janssen@amsterdam.nl", + "biography": "Raadslid en lid van de VNG-ledenraad." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "person" + }, + "slug": "persoon-a-terpstra", + "name": "A. Terpstra", + "familyName": "Terpstra", + "givenName": "A." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "person" + }, + "slug": "persoon-w-van-dam", + "name": "W. van Dam", + "familyName": "van Dam", + "givenName": "W." + } + ], + "post": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "post" + }, + "slug": "post-griffier-amsterdam", + "label": "Raadsgriffier", + "role": "secretary", + "startDate": "2021-01-15T00:00:00Z", + "governanceBody": "gemeenteraad-amsterdam" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "post" + }, + "slug": "post-voorzitter-amsterdam", + "label": "Voorzitter gemeenteraad", + "role": "chair", + "startDate": "2018-05-30T00:00:00Z", + "governanceBody": "gemeenteraad-amsterdam" + } + ], + "process-template": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "process-template" + }, + "slug": "corporate-board", + "name": "Corporate Board (BV)", + "description": "Decision process for the management board of a Dutch private limited company (BV).", + "context": "corporate", + "builtIn": true, + "initialState": "draft", + "stateMachine": { + "states": [ + { + "name": "draft" + }, + { + "name": "proposed" + }, + { + "name": "deliberating" + }, + { + "name": "voting" + }, + { + "name": "decided" + }, + { + "name": "enacted" + }, + { + "name": "archived" + } + ], + "transitions": [ + { + "name": "propose", + "from": "draft", + "to": "proposed" + }, + { + "name": "deliberate", + "from": "proposed", + "to": "deliberating" + }, + { + "name": "openVoting", + "from": "deliberating", + "to": "voting", + "chairOnly": true, + "guards": [ + "quorum_met" + ] + }, + { + "name": "decide", + "from": "voting", + "to": "decided" + }, + { + "name": "enact", + "from": "decided", + "to": "enacted" + }, + { + "name": "archive", + "from": "enacted", + "to": "archived" + } + ] + }, + "votingRule": { + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "tieBreakRule": "chair-decides" + }, + "quorumRequired": true, + "quorumRule": "Quorum per the articles of association", + "allowDecideWithoutVote": false + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "process-template" + }, + "slug": "municipal-council", + "name": "Municipal Council", + "description": "Legislative decision process for a municipal council (gemeenteraad), Gemeentewet.", + "context": "legislative", + "builtIn": true, + "initialState": "draft", + "stateMachine": { + "states": [ + { + "name": "draft" + }, + { + "name": "proposed" + }, + { + "name": "deliberating" + }, + { + "name": "voting" + }, + { + "name": "decided" + }, + { + "name": "enacted" + }, + { + "name": "archived" + } + ], + "transitions": [ + { + "name": "propose", + "from": "draft", + "to": "proposed" + }, + { + "name": "deliberate", + "from": "proposed", + "to": "deliberating" + }, + { + "name": "openVoting", + "from": "deliberating", + "to": "voting", + "chairOnly": true, + "guards": [ + "quorum_met", + "all_amendments_resolved" + ] + }, + { + "name": "decide", + "from": "voting", + "to": "decided", + "chairOnly": true + }, + { + "name": "enact", + "from": "decided", + "to": "enacted" + }, + { + "name": "archive", + "from": "enacted", + "to": "archived" + } + ] + }, + "votingRule": { + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "tieBreakRule": "rejected" + }, + "quorumRequired": true, + "quorumRule": "More than half of the seats occupied (Gemeentewet art. 20)", + "allowDecideWithoutVote": false + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "process-template" + }, + "slug": "municipal-council-urgent", + "name": "Municipal Council (urgency-enabled)", + "description": "Municipal council (gemeenteraad) process template with the urgent-decision procedure enabled: college spoedbesluit routed to a mandatory ratification stage at the next regular raadsvergadering (design seed table, municipal column).", + "context": "legislative", + "builtIn": false, + "initialState": "draft", + "stateMachine": { + "states": [ + { + "name": "draft" + }, + { + "name": "proposed" + }, + { + "name": "deliberating" + }, + { + "name": "voting" + }, + { + "name": "decided" + }, + { + "name": "enacted" + }, + { + "name": "archived" + } + ], + "transitions": [ + { + "name": "propose", + "from": "draft", + "to": "proposed" + }, + { + "name": "deliberate", + "from": "proposed", + "to": "deliberating" + }, + { + "name": "openVoting", + "from": "deliberating", + "to": "voting", + "chairOnly": true, + "guards": [ + "quorum_met", + "all_amendments_resolved" + ] + }, + { + "name": "decide", + "from": "voting", + "to": "decided", + "chairOnly": true + }, + { + "name": "enact", + "from": "decided", + "to": "enacted" + }, + { + "name": "archive", + "from": "enacted", + "to": "archived" + } + ] + }, + "votingRule": { + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "tieBreakRule": "rejected" + }, + "quorumRequired": true, + "quorumRule": "More than half of the seats occupied (Gemeentewet art. 20)", + "allowDecideWithoutVote": false, + "urgencyPolicy": { + "allowedTriggerRoles": [ + "chair" + ], + "minimumNoticeFloorHours": 24, + "responseDeadlineHours": { + "min": 12, + "max": 96 + }, + "ratificationRequired": true, + "ratifyingBody": "gemeenteraad-amsterdam" + } + } + ], + "proxy-authorization": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "proxy-authorization" + }, + "slug": "machtiging-devries-ingetrokken", + "grantor": "jan-de-vries", + "holder": "pieter-bakker", + "meeting": "raadsvergadering-2025-01-15", + "document": "00000000-0000-0000-0000-000000000000", + "signatureStatus": "signed", + "signedAt": "2026-05-01T10:00:00Z", + "revokedAt": "2026-05-20T14:30:00Z", + "revocationSignatureStatus": "signed", + "revocationSigningReference": "docudesk:sign:seed-devries-revocatie" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "proxy-authorization" + }, + "slug": "machtiging-vandam-begroting", + "grantor": "00000000-0000-0000-0000-000000000000", + "holder": "jan-de-vries", + "meeting": "raadsvergadering-2025-01-15", + "proxyVote": "stem-proxy-vandam-begroting", + "document": "00000000-0000-0000-0000-000000000000", + "signatureStatus": "signed", + "signedAt": "2026-06-02T09:15:00Z", + "signingReference": "docudesk:sign:seed-vandam-begroting", + "countersignStatus": "signed", + "countersignedAt": "2026-06-02T11:40:00Z" + } + ], + "raadsinformatiebrief": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "raadsinformatiebrief" + }, + "slug": "rib-2026-012-wachtlijsten-jeugdzorg", + "number": "RIB-2026-012", + "subject": "Wachtlijsten jeugdzorg: stand van zaken en maatregelen", + "portfolioHolder": "00000000-0000-0000-0000-000000000000", + "category": "toezegging-afdoening", + "sentAt": "2026-02-20", + "directedTo": "gemeenteraad-amsterdam", + "letterDocument": "Decidesk/Gemeenteraad Amsterdam/Raadsinformatiebrieven/RIB-2026-012 Wachtlijsten jeugdzorg.pdf", + "attachments": [ + "Decidesk/Gemeenteraad Amsterdam/Raadsinformatiebrieven/RIB-2026-012 Bijlage rapportage wachtlijsten.pdf" + ], + "agendaItem": "lijst-ingekomen-stukken-2025-01-15", + "settledCommitment": "toezegging-raadsbrief-jeugdzorg", + "lifecycle": "agendised", + "publicationDate": "2026-02-21T09:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "raadsinformatiebrief" + }, + "slug": "rib-2026-013-energietransitie", + "number": "RIB-2026-013", + "subject": "Voortgang energietransitie gebouwde omgeving", + "portfolioHolder": "00000000-0000-0000-0000-000000000000", + "category": "actieve-informatieplicht", + "sentAt": "2026-03-05", + "directedTo": "gemeenteraad-amsterdam", + "letterDocument": "Decidesk/Gemeenteraad Amsterdam/Raadsinformatiebrieven/RIB-2026-013 Voortgang energietransitie.pdf", + "lifecycle": "sent" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "raadsinformatiebrief" + }, + "slug": "rib-2026-014-afdoening-motie-fietsveiligheid", + "number": "RIB-2026-014", + "subject": "Afdoening motie Fietsveiligheid schoolroutes", + "portfolioHolder": "00000000-0000-0000-0000-000000000000", + "category": "motie-afdoening", + "sentAt": "2026-03-12", + "directedTo": "gemeenteraad-amsterdam", + "letterDocument": "Decidesk/Gemeenteraad Amsterdam/Raadsinformatiebrieven/RIB-2026-014 Afdoening motie fietsveiligheid.pdf", + "agendaItem": "lijst-ingekomen-stukken-2025-01-15", + "relatedMotion": "00000000-0000-0000-0000-000000000000", + "lifecycle": "involved-in-handling", + "publicationDate": "2026-03-13T09:00:00Z" + } + ], + "regeling": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "regeling" + }, + "slug": "afvalstoffenverordening-amsterdam", + "type": "by-law", + "citationTitle": "Afvalstoffenverordening Amsterdam", + "officialTitle": "Verordening op de inzameling en verwerking van huishoudelijke afvalstoffen Amsterdam", + "statutoryBasis": [ + "Gemeentewet art. 149", + "Wet milieubeheer art. 10.23" + ], + "determiningBody": "gemeenteraad-amsterdam", + "cvdrIdentifier": "CVDR641871", + "currentVersionNumber": 2, + "currentEffectiveDate": "2025-06-01", + "status": "in-effect" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "regeling" + }, + "slug": "beleidsregel-terrassen-amsterdam", + "type": "policy-rule", + "citationTitle": "Beleidsregel terrassen Amsterdam 2025", + "officialTitle": "Beleidsregel inzake terrasvergunningen Amsterdam 2025", + "statutoryBasis": [ + "APV Amsterdam art. 3.17" + ], + "determiningBody": "gemeenteraad-amsterdam", + "currentVersionNumber": 1, + "currentEffectiveDate": "2025-03-01", + "status": "in-effect" + } + ], + "regeling-export-package": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "regeling-export-package" + }, + "slug": "export-afvalstoffen-v2", + "regulation": "afvalstoffenverordening-amsterdam", + "versies": [ + "afvalstoffen-v2" + ], + "sourceSlug": "drop-bekendmakingen", + "status": "ready" + } + ], + "regeling-versie": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "regeling-versie" + }, + "slug": "afvalstoffen-v1", + "regulation": "afvalstoffenverordening-amsterdam", + "versionNumber": 1, + "determinedBy": "00000000-0000-0000-0000-000000000000", + "effectiveDate": "2024-01-01", + "notes": "Eerste vaststelling van de Afvalstoffenverordening Amsterdam.", + "status": "replaced" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "regeling-versie" + }, + "slug": "afvalstoffen-v2", + "regulation": "afvalstoffenverordening-amsterdam", + "versionNumber": 2, + "determinedBy": "00000000-0000-0000-0000-000000000000", + "effectiveDate": "2025-06-01", + "notes": "Wijziging 2025: gescheiden inzameling GFT-e uitgebreid naar het hele beheergebied.", + "status": "in-effect" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "regeling-versie" + }, + "slug": "terrassen-v1", + "regulation": "beleidsregel-terrassen-amsterdam", + "versionNumber": 1, + "determinedBy": "00000000-0000-0000-0000-000000000000", + "effectiveDate": "2025-03-01", + "notes": "Vaststelling beleidsregel terrassen 2025.", + "status": "in-effect" + } + ], + "rooster-regel": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "rooster-regel" + }, + "slug": "rooster-regel-auditcommissie-bakker", + "schedule": "rooster-auditcommissie", + "membership": "00000000-0000-0000-0000-000000000000", + "personName": "K. Bakker", + "role": "member", + "termNumber": 1, + "endTermDate": "2027-05-01", + "reappointable": true + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "rooster-regel" + }, + "slug": "rooster-regel-auditcommissie-jansen", + "schedule": "rooster-auditcommissie", + "membership": "00000000-0000-0000-0000-000000000000", + "personName": "S. Jansen", + "role": "member", + "termNumber": 1, + "endTermDate": "2030-09-10", + "reappointable": true + } + ], + "rooster-van-aftreden": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "rooster-van-aftreden" + }, + "slug": "rooster-auditcommissie", + "body": "auditcommissie-provincie-nh", + "generatedOn": "2026-07-01T09:00:00Z", + "generatedBy": "Griffie" + } + ], + "technische-vraag": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "technische-vraag" + }, + "slug": "tv-rib-2026-012-doorlooptijd", + "rib": "rib-2026-012-wachtlijsten-jeugdzorg", + "question": "Hoe verhoudt de genoemde gemiddelde doorlooptijd zich tot de landelijke norm?", + "setBy": "00000000-0000-0000-0000-000000000000", + "politicalGroup": "GroenLinks", + "setOn": "2026-02-24", + "answer": "De doorlooptijd ligt 12% boven de landelijke norm; het plan van aanpak voorziet in een reductie naar de norm binnen twee kwartalen.", + "answeredBy": "Afdeling Sociaal Domein", + "answeredOn": "2026-03-02", + "lifecycle": "answered", + "publicationDate": "2026-03-03T09:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "technische-vraag" + }, + "slug": "tv-rib-2026-012-regiocijfers", + "rib": "rib-2026-012-wachtlijsten-jeugdzorg", + "question": "Kunnen de wachtlijstcijfers worden uitgesplitst per regiogemeente?", + "setBy": "00000000-0000-0000-0000-000000000000", + "politicalGroup": "VVD", + "setOn": "2026-02-25", + "lifecycle": "put" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "technische-vraag" + }, + "slug": "tv-rib-2026-013-netcapaciteit", + "rib": "rib-2026-013-energietransitie", + "question": "Welke wijken lopen vertraging op door netcapaciteit?", + "setBy": "00000000-0000-0000-0000-000000000000", + "politicalGroup": "D66", + "setOn": "2026-03-08", + "lifecycle": "put" + } + ], + "termijn-regeling": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "termijn-regeling" + }, + "slug": "termijn-regeling-auditcommissie", + "body": "auditcommissie-provincie-nh", + "termDurationMonths": 48, + "notes": "Benoeming voor de duur van de raadsperiode; geen maximum aan aansluitende termijnen." + } + ], + "termijnagenda-item": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "termijnagenda-item" + }, + "slug": "lta-herziening-parkeerbeleid", + "subject": "Herziening parkeerbeleid binnenstad", + "governanceBody": "gemeenteraad-amsterdam", + "plannedPeriod": "2026-Q2", + "expectedType": "council-proposal", + "ownerType": "executive-board", + "notes": "Voortkomend uit de aangenomen motie parkeerdruk; college bereidt een raadsvoorstel voor.", + "lifecycle": "postponed", + "shiftHistory": [ + { + "van": "2026-Q1", + "toPeriod": "2026-Q2", + "reason": "Wacht op uitkomst parkeeronderzoek regio", + "door": "00000000-0000-0000-0000-000000000000", + "op": "2026-03-15T10:00:00Z" + } + ], + "originMotion": "00000000-0000-0000-0000-000000000000", + "goal": "goal-amsterdam-parkeerbeleid-kwartaal", + "publicationDate": "2026-06-20T09:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "termijnagenda-item" + }, + "slug": "lta-kadernota-2027", + "subject": "Kadernota 2027", + "governanceBody": "gemeenteraad-amsterdam", + "plannedPeriod": "2027-Q2", + "expectedType": "budget-document", + "ownerType": "executive-board", + "notes": "Reguliere jaarlijkse kadernota in de P&C-cyclus.", + "lifecycle": "planned", + "shiftHistory": [], + "originDecision": "00000000-0000-0000-0000-000000000000" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "termijnagenda-item" + }, + "slug": "lta-rib-wachtlijsten-jeugdzorg", + "subject": "RIB wachtlijsten jeugdzorg", + "governanceBody": "gemeenteraad-amsterdam", + "plannedPeriod": "2026-11", + "expectedType": "council-information-letter", + "ownerType": "portfolio-holder", + "owner": "00000000-0000-0000-0000-000000000000", + "notes": "Toegezegde raadsinformatiebrief over de aanpak van de wachtlijsten jeugdzorg.", + "lifecycle": "planned", + "shiftHistory": [], + "originCommitment": "00000000-0000-0000-0000-000000000000", + "publicationDate": "2026-06-20T09:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "termijnagenda-item" + }, + "slug": "lta-themabijeenkomst-energietransitie", + "subject": "Themabijeenkomst energietransitie", + "governanceBody": "gemeenteraad-amsterdam", + "plannedPeriod": "2027-Q1", + "expectedType": "theme-session", + "ownerType": "council-registry", + "notes": "Beeldvormende bijeenkomst ter voorbereiding op de warmtevisie.", + "lifecycle": "planned", + "shiftHistory": [], + "publicationDate": "2026-06-20T09:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "termijnagenda-item" + }, + "slug": "lta-verordening-marktgelden", + "subject": "Actualisatie verordening marktgelden", + "governanceBody": "gemeenteraad-amsterdam", + "plannedPeriod": "2026-Q1", + "expectedType": "council-proposal", + "ownerType": "portfolio-holder", + "owner": "00000000-0000-0000-0000-000000000000", + "lifecycle": "lapsed", + "shiftHistory": [], + "reasonExpired": "Opgegaan in de bredere herziening van de legesverordening", + "publicationDate": "2026-06-20T09:00:00Z" + } + ], + "toezegging": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "toezegging" + }, + "slug": "toezegging-evaluatie-afvalbeleid", + "text": "Het college zegt toe de evaluatie van het afvalbeleid gelijktijdig met de kadernota aan te bieden.", + "madeBy": "00000000-0000-0000-0000-000000000000", + "meeting": "raadsvergadering-2025-01-15", + "directedTo": "gemeenteraad-amsterdam", + "deadline": "2026-06-30", + "lifecycle": "disposed", + "settlementNotes": "Evaluatierapport aangeboden bij kadernota 2026; besproken in commissie Middelen.", + "settlementEvidence": "https://gemeente-voorbeeldingen.nl/raadsbrieven/evaluatie-afvalbeleid-2026.pdf", + "relatedMotion": "00000000-0000-0000-0000-000000000000", + "publicationDate": "2026-02-10T09:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "toezegging" + }, + "slug": "toezegging-raadsbrief-jeugdzorg", + "text": "Wethouder Van Dijk zegt toe de raad vóór 1 maart per raadsbrief te informeren over de wachtlijsten jeugdzorg.", + "madeBy": "00000000-0000-0000-0000-000000000000", + "meeting": "raadsvergadering-2025-01-15", + "agendaItem": "begroting-2026-bespreking", + "directedTo": "gemeenteraad-amsterdam", + "deadline": "2026-03-01", + "lifecycle": "open", + "publicationDate": "2026-01-20T09:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "toezegging" + }, + "slug": "toezegging-schouw-marktplein", + "text": "Wethouder Pietersen zegt toe binnen zes weken een schouw van het Marktplein te organiseren met de klankbordgroep.", + "madeBy": "00000000-0000-0000-0000-000000000000", + "meeting": "raadsvergadering-2025-01-15", + "agendaItem": "rondvraag", + "directedTo": "gemeenteraad-amsterdam", + "deadline": "2026-05-15", + "lifecycle": "in-execution", + "goal": "goal-amsterdam-klimaatneutraal-2050", + "publicationDate": "2026-02-10T09:00:00Z" + } + ], + "vote": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "vote" + }, + "slug": "stem-bakker-motie-duurzaamheid", + "value": "against", + "weight": 1, + "isProxy": false, + "castAt": "2025-04-10T21:02:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "vote" + }, + "slug": "stem-devries-motie-duurzaamheid", + "value": "for", + "weight": 1, + "isProxy": false, + "castAt": "2025-04-10T21:01:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "vote" + }, + "slug": "stem-elamrani-begroting-2026", + "value": "for", + "weight": 1, + "isProxy": false, + "castAt": "2025-04-10T21:31:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "vote" + }, + "slug": "stem-femke-begroting-2027", + "value": "for", + "weight": 1, + "isProxy": false, + "castAt": "2026-04-15T21:05:00Z", + "castAs": "in-person", + "votingRound": "stemming-begroting-2027-gemeenteraad", + "participant": "femke-halsema" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "vote" + }, + "slug": "stem-marie-begroting-2027", + "value": "for", + "weight": 1, + "isProxy": false, + "castAt": "2026-04-15T21:06:00Z", + "castAs": "in-person", + "votingRound": "stemming-begroting-2027-gemeenteraad", + "participant": "marie-janssen" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "vote" + }, + "slug": "stem-proxy-vandam-begroting", + "value": "for", + "weight": 1, + "isProxy": true, + "castAt": "2025-04-10T21:32:00Z" + } + ], + "voting-round": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "voting-round" + }, + "slug": "stemming-amendement-a", + "votingMethod": "for-against-abstain", + "isSecret": false, + "openedAt": "2025-04-10T20:55:00Z", + "closedAt": "2025-04-10T21:00:00Z", + "quorumWith": true, + "result": "rejected", + "votesFor": 11, + "votesAgainst": 20, + "votesAbstain": 2 + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "voting-round" + }, + "slug": "stemming-begroting-2026", + "votingMethod": "for-against-abstain", + "isSecret": false, + "openedAt": "2025-04-10T21:30:00Z", + "closedAt": "2025-04-10T21:38:00Z", + "quorumWith": true, + "result": "adopted", + "votesFor": 25, + "votesAgainst": 6, + "votesAbstain": 2 + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "voting-round" + }, + "slug": "stemming-begroting-2027-gemeenteraad", + "votingMethod": "for-against-abstain", + "isSecret": false, + "openedAt": "2026-04-15T21:00:00Z", + "closedAt": "2026-04-15T21:15:00Z", + "quorumWith": true, + "result": "adopted", + "votesFor": 28, + "votesAgainst": 3, + "votesAbstain": 2, + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "decisionStage": "stage-begroting-2027-3-dec" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "voting-round" + }, + "slug": "stemming-motie-duurzaamheid-2025", + "votingMethod": "for-against-abstain", + "isSecret": false, + "openedAt": "2025-04-10T21:00:00Z", + "closedAt": "2025-04-10T21:05:00Z", + "quorumWith": true, + "result": "adopted", + "votesFor": 28, + "votesAgainst": 3, + "votesAbstain": 2 + } + ], + "vragenuur-configuratie": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "vragenuur-configuratie" + }, + "slug": "vragenuur-configuratie-gemeenteraad", + "governanceBody": "gemeenteraad-amsterdam", + "submissionPeriodHours": 24, + "interpellationSupportThresholdType": "fraction", + "interpellationSupportThresholdValue": 0.2 + } + ], + "woo-bestuursorgaan": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "woo-bestuursorgaan" + }, + "slug": "woo-bestuursorgaan-gemeenteraad-amsterdam", + "governanceBody": "gemeenteraad-amsterdam", + "governingBody": "gm0344", + "label": "Gemeenteraad (example)", + "active": true, + "notes": "EXAMPLE bestuursorgaan TOOI gemeente-identificatie only (gm0344 is the id the records-management-archiving MDTO archiefvormer convention uses as its documented example). Replace with the real bestuursorgaan identifier of this governance body at implementation. The instance-wide default bestuursorgaan lives in app config (admin Woo section, REQ-WOO-006); this object is the per-governance-body override." + } + ], + "woo-categorie-mapping": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "woo-categorie-mapping" + }, + "slug": "woo-map-besluitenlijst", + "objectType": "decision-list", + "informatiecategorie": "https://identifier.overheid.nl/tooi/def/thes/kern/c_PLACEHOLDER_vergaderstukken-decentrale-overheden", + "informatiecategorieLabel": "Vergaderstukken decentrale overheden", + "active": true, + "notes": "Generated decision-list document (p2-minutes-and-decisions-core-t1). PLACEHOLDER informatiecategorie — copy verbatim from the published TOOI waardelijst at implementation." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "woo-categorie-mapping" + }, + "slug": "woo-map-decision", + "objectType": "decision", + "informatiecategorie": "https://identifier.overheid.nl/tooi/def/thes/kern/c_PLACEHOLDER_vergaderstukken-decentrale-overheden", + "informatiecategorieLabel": "Vergaderstukken decentrale overheden", + "active": true, + "notes": "ORI Besluit. PLACEHOLDER informatiecategorie — copy verbatim from the published TOOI waardelijst at implementation." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "woo-categorie-mapping" + }, + "slug": "woo-map-meeting-agenda", + "objectType": "meeting-agenda", + "informatiecategorie": "https://identifier.overheid.nl/tooi/def/thes/kern/c_PLACEHOLDER_vergaderstukken-decentrale-overheden", + "informatiecategorieLabel": "Vergaderstukken decentrale overheden", + "active": true, + "notes": "Meeting agenda payload. PLACEHOLDER informatiecategorie — copy the exact vergaderstukken-decentrale-overheden concept URI verbatim from the published TOOI waardelijst at implementation." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "woo-categorie-mapping" + }, + "slug": "woo-map-minutes", + "objectType": "minutes", + "informatiecategorie": "https://identifier.overheid.nl/tooi/def/thes/kern/c_PLACEHOLDER_vergaderstukken-decentrale-overheden", + "informatiecategorieLabel": "Vergaderstukken decentrale overheden", + "active": true, + "notes": "ORI Verslag. PLACEHOLDER informatiecategorie — copy verbatim from the published TOOI waardelijst at implementation." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "woo-categorie-mapping" + }, + "slug": "woo-map-motie", + "objectType": "motion", + "informatiecategorie": "https://identifier.overheid.nl/tooi/def/thes/kern/c_PLACEHOLDER_vergaderstukken-decentrale-overheden", + "informatiecategorieLabel": "Vergaderstukken decentrale overheden", + "active": true, + "notes": "Inert until the Motie schema (sibling motie-amendement-administratie) lands — REQ-WOO-001. PLACEHOLDER informatiecategorie — copy verbatim at implementation." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "woo-categorie-mapping" + }, + "slug": "woo-map-raadsinformatiebrief", + "objectType": "council-information-letter", + "informatiecategorie": "https://identifier.overheid.nl/tooi/def/thes/kern/c_PLACEHOLDER_vergaderstukken-decentrale-overheden", + "informatiecategorieLabel": "Vergaderstukken decentrale overheden", + "active": true, + "notes": "Predicate-published (sibling raadsinformatiebrieven, fragment 51). PLACEHOLDER informatiecategorie — copy verbatim at implementation." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "woo-categorie-mapping" + }, + "slug": "woo-map-regeling", + "objectType": "arrangement", + "informatiecategorie": "https://identifier.overheid.nl/tooi/def/thes/kern/c_PLACEHOLDER_wetten-en-algemeen-verbindende-voorschriften", + "informatiecategorieLabel": "Wetten en algemeen verbindende voorschriften", + "active": true, + "notes": "Inert until the Regeling schema (sibling verordeningenregister) lands — REQ-WOO-001. PLACEHOLDER informatiecategorie — copy the exact wetten-en-algemeen-verbindende-voorschriften concept URI verbatim at implementation." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "woo-categorie-mapping" + }, + "slug": "woo-map-toezegging", + "objectType": "commitment", + "informatiecategorie": "https://identifier.overheid.nl/tooi/def/thes/kern/c_PLACEHOLDER_vergaderstukken-decentrale-overheden", + "informatiecategorieLabel": "Vergaderstukken decentrale overheden", + "active": true, + "notes": "Predicate-published (sibling toezeggingen-ingekomen-stukken, fragment 45). PLACEHOLDER informatiecategorie — copy verbatim at implementation." + } + ], + "zienswijze": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "zienswijze" + }, + "slug": "zienswijze-noorderbrug-begroting-2027", + "ronde": "zienswijzeronde-begroting-2027", + "participant": "gemeenteraad-noorderbrug", + "deadline": "2026-06-15", + "position": "positive-with-reservations", + "text": "De raad stemt in met de ontwerpbegroting, met de kanttekening dat de indexatie van de gemeentelijke bijdrage maximaal 3% mag bedragen.", + "submittedDate": "2026-06-10T00:00:00Z", + "decision": "00000000-0000-0000-0000-000000000000", + "processing": "partly-adopted", + "processingNotes": "Indexatie verlaagd naar 3,2%; volledige inwilliging niet mogelijk binnen de CAO-ontwikkeling.", + "status": "processed" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "zienswijze" + }, + "slug": "zienswijze-noorderbrug-wijziging-gr", + "ronde": "zienswijzeronde-wijziging-gr-2026", + "participant": "gemeenteraad-noorderbrug", + "deadline": "2026-09-30", + "status": "outstanding" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "zienswijze" + }, + "slug": "zienswijze-oostwoud-begroting-2027", + "ronde": "zienswijzeronde-begroting-2027", + "participant": "gemeenteraad-oostwoud", + "deadline": "2026-06-15", + "position": "positive", + "text": "De raad stemt zonder opmerkingen in met de ontwerpbegroting 2027.", + "submittedDate": "2026-06-02T00:00:00Z", + "processing": "adopted", + "processingNotes": "Voor kennisgeving aangenomen.", + "status": "processed" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "zienswijze" + }, + "slug": "zienswijze-zuidermeer-begroting-2027", + "ronde": "zienswijzeronde-begroting-2027", + "participant": "gemeenteraad-zuidermeer", + "deadline": "2026-06-15", + "status": "not-submitted" + } + ], + "zienswijzeronde": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "zienswijzeronde" + }, + "slug": "zienswijzeronde-begroting-2027", + "title": "Zienswijzeronde ontwerpbegroting 2027 NOZ organisatie", + "sharedBody": "bestuur-noz-organisatie", + "subjectType": "draft-budget", + "subjectDescription": "Ontwerpbegroting 2027, aangeboden aan de raden conform art. 35 Wgr.", + "deadline": "2026-06-15", + "cyclusStep": "00000000-0000-0000-0000-000000000000", + "status": "processing" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "zienswijzeronde" + }, + "slug": "zienswijzeronde-wijziging-gr-2026", + "title": "Zienswijzeronde wijziging gemeenschappelijke regeling", + "sharedBody": "bestuur-noz-organisatie", + "subjectType": "amendment-of-arrangement", + "subjectDescription": "Voorstel tot wijziging van de regeling i.v.m. taakuitbreiding vergunningverlening.", + "deadline": "2026-09-30", + "status": "opened" + } + ] + } + } + }, + "paths": {}, + "components": {} +} diff --git a/lib/Settings/profiles/works-council.json b/lib/Settings/profiles/works-council.json new file mode 100644 index 000000000..9d5db33ce --- /dev/null +++ b/lib/Settings/profiles/works-council.json @@ -0,0 +1,755 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Decidiq example set: Works council", + "version": "1.0.0", + "description": "A works council inside a company. Advice requests, consent requests and staff consultation." + }, + "x-openregister": { + "type": "profile", + "app": "decidiq", + "profile": { + "id": "works-council", + "label": "Works council", + "description": "A works council inside a company. Advice requests, consent requests and staff consultation.", + "order": 4, + "objectCount": 45 + }, + "description": "An example set an operator picks in the first-time setup wizard (ADR-042). NEVER imported on install: the register.d fragments declare schemas only, so a bare install has zero objects. Every object carries @self.configuration/register/schema so the import resolves the live decidiq register WITHOUT this descriptor declaring components.registers. That is deliberate and load-bearing: ImportHandler::importRegister() calls setApplication($appId) unconditionally on an existing register, so a descriptor that declared the register would re-point the decidiq register at this profile config id and hydrate over its authorization baseline. Verified on a live instance: importing this shape left application=decidiq, version and authorization byte-identical. Import is idempotent by slug, so loading a profile twice adds nothing. Descriptors live in this SUBDIRECTORY on purpose: RegisterDescriptorService scans lib/Settings/*.json non-recursively and matches descriptors by declared register slug, so four profile files in lib/Settings would collide with each other and with decidesk_register.json.", + "seedData": { + "description": "Example objects for the works council set.", + "objects": { + "action-item": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "action-item" + }, + "slug": "or-actie-sociaal-plan", + "title": "Sociaal plan opvragen bij de bestuurder", + "description": "De secretaris vraagt het concept-sociaal plan op en verspreidt het onder de OR-leden.", + "assignee": "or-youssef-benali", + "dueDate": "2026-03-13", + "taskStatus": "completed", + "completedAt": "2026-03-13T12:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "action-item" + }, + "slug": "or-actie-achterban-terugkoppeling", + "title": "Terugkoppeling achterbanraadpleging opstellen", + "description": "De uitkomst van de raadpleging wordt samengevat en aan de achterban teruggekoppeld.", + "assignee": "or-linda-vermeer", + "dueDate": "2026-03-02", + "taskStatus": "completed", + "completedAt": "2026-03-02T12:00:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "action-item" + }, + "slug": "or-actie-zelfroosteren-analyse", + "title": "Effect zelfroosteren op de productieploegen uitzoeken", + "description": "Voor de instemmingsaanvraag wordt in kaart gebracht wat zelfroosteren betekent voor de ploegendiensten.", + "assignee": "or-dennis-kok", + "dueDate": "2026-06-10", + "taskStatus": "in-progress" + } + ], + "agenda-item": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "or-2026-01-adviesaanvraag-ict", + "title": "Adviesaanvraag uitbesteding ICT-beheer", + "itemType": "decision", + "orderNumber": 1, + "estimatedDuration": 60, + "meeting": "or-vergadering-2026-01-14", + "description": "Behandeling van de adviesaanvraag art. 25 WOR over de uitbesteding van het ICT-beheer." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "or-2026-01-achterban", + "title": "Opzet achterbanraadpleging thuiswerkregeling", + "itemType": "discussion", + "orderNumber": 2, + "estimatedDuration": 30, + "meeting": "or-vergadering-2026-01-14", + "description": "Vaststellen van de vraagstelling voor de raadpleging van de achterban." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "or-overleg-2026-02-reorganisatie", + "title": "Voorgenomen reorganisatie logistiek", + "itemType": "discussion", + "orderNumber": 1, + "estimatedDuration": 45, + "meeting": "or-overlegvergadering-2026-02-18", + "description": "Toelichting door de bestuurder op de voorgenomen inkrimping van de afdeling logistiek." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "or-overleg-2026-02-ict", + "title": "Advies OR over uitbesteding ICT-beheer", + "itemType": "decision", + "orderNumber": 2, + "estimatedDuration": 30, + "meeting": "or-overlegvergadering-2026-02-18", + "description": "De OR licht zijn advies met voorwaarden toe aan de bestuurder." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "or-2026-06-instemming-werktijden", + "title": "Instemmingsverzoek werktijdenregeling", + "itemType": "decision", + "orderNumber": 1, + "estimatedDuration": 60, + "meeting": "or-vergadering-2026-06-17", + "description": "Besluitvorming over het instemmingsverzoek art. 27 WOR over zelfroosteren." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "agenda-item" + }, + "slug": "or-2026-06-rondvraag", + "title": "Rondvraag", + "itemType": "informational", + "orderNumber": 2, + "estimatedDuration": 10, + "meeting": "or-vergadering-2026-06-17" + } + ], + "consultation-request": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "consultation-request" + }, + "slug": "adviesaanvraag-outsourcing-ict", + "type": "adviceRequest", + "worArticle": "art. 25 lid 1 sub n WOR", + "subject": "Uitbesteding ICT-beheer aan externe dienstverlener", + "director": "acme-bestuurder-hilde-jansen", + "governanceBody": "ondernemingsraad-acme", + "receivedDate": "2026-01-06", + "requestedResponseDate": "2026-03-01", + "consultationMeeting": "or-overlegvergadering-2026-02-18", + "agendaItem": "or-2026-01-adviesaanvraag-ict", + "responseOutcome": "advice-with-conditions", + "responseText": "De OR adviseert positief onder voorwaarde van een sociaal plan en een evaluatiemoment na 12 maanden.", + "responseDate": "2026-02-24", + "relatedDecision": "or-advies-uitbesteding-ict", + "decisionOutcome": "in-line-with-advice", + "decisionText": "De bestuurder neemt het advies over en zegt een sociaal plan en een evaluatie na 12 maanden toe.", + "decisionDate": "2026-03-05", + "lifecycle": "completed" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "consultation-request" + }, + "slug": "adviesaanvraag-reorganisatie-logistiek", + "type": "adviceRequest", + "worArticle": "art. 25 lid 1 sub d WOR", + "subject": "Voorgenomen reorganisatie afdeling logistiek (inkrimping 12 fte)", + "director": "acme-bestuurder-hilde-jansen", + "governanceBody": "ondernemingsraad-acme", + "receivedDate": "2026-02-09", + "requestedResponseDate": "2026-04-17", + "consultationMeeting": "or-overlegvergadering-2026-02-18", + "agendaItem": "or-overleg-2026-02-reorganisatie", + "suspensionTo": "2026-05-15", + "lifecycle": "consultationMeeting" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "consultation-request" + }, + "slug": "instemmingsverzoek-werktijdenregeling", + "type": "consent-request", + "worArticle": "art. 27 lid 1 sub b WOR", + "subject": "Wijziging werktijdenregeling: invoering zelfroosteren productie", + "director": "acme-bestuurder-hilde-jansen", + "governanceBody": "ondernemingsraad-acme", + "receivedDate": "2026-05-11", + "requestedResponseDate": "2026-07-01", + "agendaItem": "or-2026-06-instemming-werktijden", + "constituencyConsultation": "achterban-or-thuiswerkregeling", + "lifecycle": "constituencyConsultation" + } + ], + "decision": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "or-advies-uitbesteding-ict", + "decisionType": "report-adoption", + "title": "Advies OR over uitbesteding ICT-beheer", + "text": "De ondernemingsraad adviseert positief over de uitbesteding van het ICT-beheer, onder voorwaarde van een sociaal plan voor de zes betrokken medewerkers en een evaluatie na 12 maanden.", + "decisionDate": "2026-02-18T14:45:00Z", + "outcome": "adopted", + "isPublished": "internal", + "legalBasis": "art. 25 lid 1 sub n WOR", + "lifecycle": "enacted", + "enactedAt": "2026-02-24T09:00:00Z", + "voteType": "named", + "voteThreshold": "simple-majority", + "meeting": "or-overlegvergadering-2026-02-18", + "agendaItem": "or-overleg-2026-02-ict" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision" + }, + "slug": "beleid-thuiswerkregeling", + "decisionType": "policy", + "title": "Vaststelling thuiswerkregeling", + "text": "De organisatie stelt de thuiswerkregeling 2026 vast: standaard twee thuiswerkdagen per week, met een vergoeding conform de fiscale onbelaste norm.", + "lifecycle": "enacted", + "outcome": "adopted", + "decisionDate": "2026-03-18T11:00:00Z", + "isPublished": "public" + } + ], + "decision-template": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "decision-template" + }, + "slug": "works-council-advice", + "name": "Works council advice request", + "description": "The route a WOR advice or consent request travels: received, consulted, decided, sent to the director.", + "decisionType": "report-adoption", + "context": "corporate", + "templateCategory": "works-council-consultation", + "builtIn": true, + "quorumRequired": true, + "quorumRule": "majority-of-seats", + "votingRule": { + "threshold": "simple-majority", + "abstentionHandling": "exclude" + }, + "allowDecideWithoutVote": false, + "regulationSource": "Wet op de ondernemingsraden, art. 25 en art. 27", + "checklist": [] + } + ], + "governance-body": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "governance-body" + }, + "slug": "ondernemingsraad-acme", + "name": "Ondernemingsraad ACME B.V.", + "bodyType": "works-council", + "domain": "medezeggenschap", + "statutoryBasis": "Wet op de ondernemingsraden (WOR)", + "votingDefault": "for-against-abstain", + "quorum": 4, + "active": true, + "termStart": "2025-04-01T00:00:00Z", + "termEnd": "2029-03-31T00:00:00Z", + "parentBody": "raad-van-bestuur-acme-bv" + } + ], + "meeting": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "meeting" + }, + "slug": "or-vergadering-2026-01-14", + "title": "OR-vergadering 14 januari 2026", + "meetingType": "regular", + "governanceBody": "ondernemingsraad-acme", + "scheduledDate": "2026-01-14T09:30:00Z", + "endDate": "2026-01-14T12:00:00Z", + "location": "ACME B.V., vergaderruimte Noord", + "meetingMode": "in-person", + "lifecycle": "closed", + "quorumRequired": 4, + "chair": "or-sanne-de-groot", + "isPublic": false + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "meeting" + }, + "slug": "or-overlegvergadering-2026-02-18", + "title": "Overlegvergadering 18 februari 2026", + "meetingType": "regular", + "governanceBody": "ondernemingsraad-acme", + "scheduledDate": "2026-02-18T13:00:00Z", + "endDate": "2026-02-18T15:30:00Z", + "location": "ACME B.V., directiekamer", + "meetingMode": "hybrid", + "lifecycle": "closed", + "quorumRequired": 4, + "chair": "or-sanne-de-groot", + "isPublic": false + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "meeting" + }, + "slug": "or-vergadering-2026-06-17", + "title": "OR-vergadering 17 juni 2026", + "meetingType": "regular", + "governanceBody": "ondernemingsraad-acme", + "scheduledDate": "2026-06-17T09:30:00Z", + "endDate": "2026-06-17T12:00:00Z", + "location": "ACME B.V., vergaderruimte Noord", + "meetingMode": "in-person", + "lifecycle": "scheduled", + "quorumRequired": 4, + "chair": "or-sanne-de-groot", + "isPublic": false + } + ], + "member-consultation": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "member-consultation" + }, + "slug": "achterban-or-thuiswerkregeling", + "question": "Wat vindt de achterban van de voorgestelde thuiswerkregeling (instemmingsaanvraag art. 27 WOR)?", + "description": "Informele raadpleging van de achterban voor het OR-besluit over de instemmingsaanvraag.", + "responseType": "open-text", + "audienceType": "nc-group", + "audienceGroup": "or-achterban-acme", + "agendaItem": "or-2026-01-achterban", + "opensAt": "2026-02-01T09:00:00Z", + "closesAt": "2026-02-15T17:00:00Z", + "anonymousResponses": true, + "lifecycle": "processed", + "results": { + "audienceSize": 12, + "responseCount": 9, + "openTextDigest": "Meerderheid positief. Zorgen over de bereikbaarheid van de servicedesk en over de productieploegen, die niet thuis kunnen werken." + } + } + ], + "member-consultation-response": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "member-consultation-response" + }, + "slug": "respons-or-achterban-1", + "consultation": "achterban-or-thuiswerkregeling", + "respondentId": "pdevries", + "openText": "Positief, maar de regeling moet ook voor de productieploegen een alternatief bieden.", + "submittedAt": "2026-02-03T12:05:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "member-consultation-response" + }, + "slug": "respons-or-achterban-2", + "consultation": "achterban-or-thuiswerkregeling", + "respondentId": "mbakker", + "openText": "Twee vaste thuiswerkdagen werkt goed. Graag wel duidelijkheid over de bezetting van de servicedesk.", + "submittedAt": "2026-02-05T08:40:00Z" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "member-consultation-response" + }, + "slug": "respons-or-achterban-3", + "consultation": "achterban-or-thuiswerkregeling", + "respondentId": "janssen", + "openText": "Ik mis een regeling voor de reiskostenvergoeding op thuiswerkdagen.", + "submittedAt": "2026-02-11T16:20:00Z" + } + ], + "membership": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "membership" + }, + "slug": "lidmaatschap-or-de-groot", + "role": "chair", + "person": "or-sanne-de-groot", + "governanceBody": "ondernemingsraad-acme", + "votingWeight": 1, + "startDate": "2025-04-01", + "post": "post-or-voorzitter-acme" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "membership" + }, + "slug": "lidmaatschap-or-benali", + "role": "secretary", + "person": "or-youssef-benali", + "governanceBody": "ondernemingsraad-acme", + "votingWeight": 1, + "startDate": "2025-04-01", + "post": "post-or-secretaris-acme" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "membership" + }, + "slug": "lidmaatschap-or-vermeer", + "role": "member", + "person": "or-linda-vermeer", + "governanceBody": "ondernemingsraad-acme", + "votingWeight": 1, + "startDate": "2025-04-01" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "membership" + }, + "slug": "lidmaatschap-or-kok", + "role": "member", + "person": "or-dennis-kok", + "governanceBody": "ondernemingsraad-acme", + "votingWeight": 1, + "startDate": "2025-04-01" + } + ], + "minutes": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "minutes" + }, + "slug": "notulen-or-2026-01-14", + "title": "Notulen OR-vergadering 14 januari 2026", + "lifecycle": "approved", + "version": 2, + "approvedAt": "2026-02-18T13:10:00Z", + "meeting": "or-vergadering-2026-01-14" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "minutes" + }, + "slug": "notulen-or-overleg-2026-02-18", + "title": "Notulen overlegvergadering 18 februari 2026", + "lifecycle": "review", + "version": 1, + "meeting": "or-overlegvergadering-2026-02-18" + } + ], + "participant": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "participant" + }, + "slug": "or-p-sanne-de-groot", + "displayName": "Sanne de Groot", + "role": "chair", + "email": "s.degroot@acme.nl", + "joinedAt": "2025-04-01T00:00:00Z", + "votingWeight": 1, + "attendanceStatus": "present", + "participantType": "in-person", + "governanceBody": "ondernemingsraad-acme" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "participant" + }, + "slug": "or-p-youssef-benali", + "displayName": "Youssef Benali", + "role": "secretary", + "email": "y.benali@acme.nl", + "joinedAt": "2025-04-01T00:00:00Z", + "votingWeight": 1, + "attendanceStatus": "present", + "participantType": "in-person", + "governanceBody": "ondernemingsraad-acme" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "participant" + }, + "slug": "or-p-linda-vermeer", + "displayName": "Linda Vermeer", + "role": "member", + "email": "l.vermeer@acme.nl", + "joinedAt": "2025-04-01T00:00:00Z", + "votingWeight": 1, + "attendanceStatus": "present", + "participantType": "in-person", + "governanceBody": "ondernemingsraad-acme" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "participant" + }, + "slug": "or-p-dennis-kok", + "displayName": "Dennis Kok", + "role": "member", + "email": "d.kok@acme.nl", + "joinedAt": "2025-04-01T00:00:00Z", + "votingWeight": 1, + "attendanceStatus": "present", + "participantType": "in-person", + "governanceBody": "ondernemingsraad-acme" + } + ], + "person": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "person" + }, + "slug": "or-sanne-de-groot", + "name": "Sanne de Groot", + "givenName": "Sanne", + "familyName": "de Groot", + "gender": "female", + "email": "s.degroot@acme.nl", + "biography": "Voorzitter van de ondernemingsraad, teamleider logistiek." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "person" + }, + "slug": "or-youssef-benali", + "name": "Youssef Benali", + "givenName": "Youssef", + "familyName": "Benali", + "gender": "male", + "email": "y.benali@acme.nl", + "biography": "Secretaris van de ondernemingsraad, medewerker ICT-beheer." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "person" + }, + "slug": "or-linda-vermeer", + "name": "Linda Vermeer", + "givenName": "Linda", + "familyName": "Vermeer", + "gender": "female", + "email": "l.vermeer@acme.nl", + "biography": "OR-lid namens de productieploegen." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "person" + }, + "slug": "or-dennis-kok", + "name": "Dennis Kok", + "givenName": "Dennis", + "familyName": "Kok", + "gender": "male", + "email": "d.kok@acme.nl", + "biography": "OR-lid namens de servicedesk." + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "person" + }, + "slug": "acme-bestuurder-hilde-jansen", + "name": "Hilde Jansen", + "givenName": "Hilde", + "familyName": "Jansen", + "gender": "female", + "email": "h.jansen@acme.nl", + "biography": "Bestuurder in de zin van de WOR, directeur bedrijfsvoering ACME B.V." + } + ], + "post": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "post" + }, + "slug": "post-or-voorzitter-acme", + "label": "OR-voorzitter", + "role": "chair", + "startDate": "2025-04-01T00:00:00Z", + "governanceBody": "ondernemingsraad-acme" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "post" + }, + "slug": "post-or-secretaris-acme", + "label": "OR-secretaris", + "role": "secretary", + "startDate": "2025-04-01T00:00:00Z", + "governanceBody": "ondernemingsraad-acme" + } + ], + "vote": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "vote" + }, + "slug": "stem-or-de-groot-ict", + "value": "for", + "weight": 1, + "isProxy": false, + "castAt": "2026-02-18T14:40:00Z", + "castAs": "in-person", + "votingRound": "stemming-or-advies-ict", + "participant": "or-p-sanne-de-groot" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "vote" + }, + "slug": "stem-or-benali-ict", + "value": "for", + "weight": 1, + "isProxy": false, + "castAt": "2026-02-18T14:40:00Z", + "castAs": "in-person", + "votingRound": "stemming-or-advies-ict", + "participant": "or-p-youssef-benali" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "vote" + }, + "slug": "stem-or-vermeer-ict", + "value": "for", + "weight": 1, + "isProxy": false, + "castAt": "2026-02-18T14:40:00Z", + "castAs": "in-person", + "votingRound": "stemming-or-advies-ict", + "participant": "or-p-linda-vermeer" + }, + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "vote" + }, + "slug": "stem-or-kok-ict", + "value": "abstain", + "weight": 1, + "isProxy": false, + "castAt": "2026-02-18T14:40:00Z", + "castAs": "in-person", + "votingRound": "stemming-or-advies-ict", + "participant": "or-p-dennis-kok" + } + ], + "voting-round": [ + { + "@self": { + "configuration": "decidiq", + "register": "decidiq", + "schema": "voting-round" + }, + "slug": "stemming-or-advies-ict", + "votingMethod": "for-against-abstain", + "isSecret": false, + "openedAt": "2026-02-18T14:35:00Z", + "closedAt": "2026-02-18T14:44:00Z", + "quorumWith": true, + "result": "adopted", + "votesFor": 3, + "votesAgainst": 0, + "votesAbstain": 1, + "voteThreshold": "simple-majority", + "abstentionHandling": "exclude", + "voteBase": 4 + } + ] + } + } + }, + "paths": {}, + "components": {} +} diff --git a/lib/Settings/register.d/43-process-config-v1.json b/lib/Settings/register.d/43-process-config-v1.json index e19a1475d..55ba2c5a0 100644 --- a/lib/Settings/register.d/43-process-config-v1.json +++ b/lib/Settings/register.d/43-process-config-v1.json @@ -1,387 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Process template seed data (planted via OpenRegister x-openregister.seedData path).", - "objects": { - "process-template": [ - { - "slug": "association-alv", - "name": "Association ALV", - "description": "Standard decision process for a Dutch association general meeting (ALV), BW Book 2.", - "context": "association", - "builtIn": true, - "initialState": "draft", - "stateMachine": { - "states": [ - { - "name": "draft" - }, - { - "name": "proposed" - }, - { - "name": "deliberating" - }, - { - "name": "voting" - }, - { - "name": "decided" - }, - { - "name": "enacted" - }, - { - "name": "archived" - } - ], - "transitions": [ - { - "name": "propose", - "from": "draft", - "to": "proposed" - }, - { - "name": "deliberate", - "from": "proposed", - "to": "deliberating" - }, - { - "name": "openVoting", - "from": "deliberating", - "to": "voting", - "chairOnly": true, - "guards": [ - "quorum_met" - ] - }, - { - "name": "decide", - "from": "voting", - "to": "decided" - }, - { - "name": "enact", - "from": "decided", - "to": "enacted" - }, - { - "name": "archive", - "from": "enacted", - "to": "archived" - } - ] - }, - "votingRule": { - "voteThreshold": "simple-majority", - "abstentionHandling": "exclude", - "tieBreakRule": "rejected" - }, - "quorumRequired": true, - "quorumRule": "50%+1 of members present or represented", - "allowDecideWithoutVote": false - }, - { - "slug": "association-board", - "name": "Association Board", - "description": "Decision process for an association board (bestuur).", - "context": "association", - "builtIn": true, - "initialState": "draft", - "stateMachine": { - "states": [ - { - "name": "draft" - }, - { - "name": "proposed" - }, - { - "name": "deliberating" - }, - { - "name": "voting" - }, - { - "name": "decided" - }, - { - "name": "enacted" - }, - { - "name": "archived" - } - ], - "transitions": [ - { - "name": "propose", - "from": "draft", - "to": "proposed" - }, - { - "name": "deliberate", - "from": "proposed", - "to": "deliberating" - }, - { - "name": "openVoting", - "from": "deliberating", - "to": "voting", - "chairOnly": true, - "guards": [ - "quorum_met" - ] - }, - { - "name": "decide", - "from": "voting", - "to": "decided" - }, - { - "name": "enact", - "from": "decided", - "to": "enacted" - }, - { - "name": "archive", - "from": "enacted", - "to": "archived" - } - ] - }, - "votingRule": { - "voteThreshold": "simple-majority", - "abstentionHandling": "exclude", - "tieBreakRule": "chair-decides" - }, - "quorumRequired": true, - "quorumRule": "Majority of board members present", - "allowDecideWithoutVote": false - }, - { - "slug": "corporate-board", - "name": "Corporate Board (BV)", - "description": "Decision process for the management board of a Dutch private limited company (BV).", - "context": "corporate", - "builtIn": true, - "initialState": "draft", - "stateMachine": { - "states": [ - { - "name": "draft" - }, - { - "name": "proposed" - }, - { - "name": "deliberating" - }, - { - "name": "voting" - }, - { - "name": "decided" - }, - { - "name": "enacted" - }, - { - "name": "archived" - } - ], - "transitions": [ - { - "name": "propose", - "from": "draft", - "to": "proposed" - }, - { - "name": "deliberate", - "from": "proposed", - "to": "deliberating" - }, - { - "name": "openVoting", - "from": "deliberating", - "to": "voting", - "chairOnly": true, - "guards": [ - "quorum_met" - ] - }, - { - "name": "decide", - "from": "voting", - "to": "decided" - }, - { - "name": "enact", - "from": "decided", - "to": "enacted" - }, - { - "name": "archive", - "from": "enacted", - "to": "archived" - } - ] - }, - "votingRule": { - "voteThreshold": "simple-majority", - "abstentionHandling": "exclude", - "tieBreakRule": "chair-decides" - }, - "quorumRequired": true, - "quorumRule": "Quorum per the articles of association", - "allowDecideWithoutVote": false - }, - { - "slug": "municipal-council", - "name": "Municipal Council", - "description": "Legislative decision process for a municipal council (gemeenteraad), Gemeentewet.", - "context": "legislative", - "builtIn": true, - "initialState": "draft", - "stateMachine": { - "states": [ - { - "name": "draft" - }, - { - "name": "proposed" - }, - { - "name": "deliberating" - }, - { - "name": "voting" - }, - { - "name": "decided" - }, - { - "name": "enacted" - }, - { - "name": "archived" - } - ], - "transitions": [ - { - "name": "propose", - "from": "draft", - "to": "proposed" - }, - { - "name": "deliberate", - "from": "proposed", - "to": "deliberating" - }, - { - "name": "openVoting", - "from": "deliberating", - "to": "voting", - "chairOnly": true, - "guards": [ - "quorum_met", - "all_amendments_resolved" - ] - }, - { - "name": "decide", - "from": "voting", - "to": "decided", - "chairOnly": true - }, - { - "name": "enact", - "from": "decided", - "to": "enacted" - }, - { - "name": "archive", - "from": "enacted", - "to": "archived" - } - ] - }, - "votingRule": { - "voteThreshold": "simple-majority", - "abstentionHandling": "exclude", - "tieBreakRule": "rejected" - }, - "quorumRequired": true, - "quorumRule": "More than half of the seats occupied (Gemeentewet art. 20)", - "allowDecideWithoutVote": false - }, - { - "slug": "operational-team", - "name": "Operational Team", - "description": "Lightweight decision process for an operational/management team; formal voting rounds are optional.", - "context": "operations", - "builtIn": true, - "initialState": "draft", - "stateMachine": { - "states": [ - { - "name": "draft" - }, - { - "name": "proposed" - }, - { - "name": "deliberating" - }, - { - "name": "decided" - }, - { - "name": "enacted" - }, - { - "name": "archived" - } - ], - "transitions": [ - { - "name": "propose", - "from": "draft", - "to": "proposed" - }, - { - "name": "deliberate", - "from": "proposed", - "to": "deliberating" - }, - { - "name": "decide", - "from": "deliberating", - "to": "decided" - }, - { - "name": "enact", - "from": "decided", - "to": "enacted" - }, - { - "name": "archive", - "from": "enacted", - "to": "archived" - } - ] - }, - "votingRule": { - "voteThreshold": "simple-majority", - "abstentionHandling": "exclude", - "tieBreakRule": "rejected" - }, - "quorumRequired": false, - "quorumRule": "No formal quorum", - "allowDecideWithoutVote": true - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/45-toezeggingen-ingekomen-stukken.json b/lib/Settings/register.d/45-toezeggingen-ingekomen-stukken.json index 5e9bd7bf3..417946378 100644 --- a/lib/Settings/register.d/45-toezeggingen-ingekomen-stukken.json +++ b/lib/Settings/register.d/45-toezeggingen-ingekomen-stukken.json @@ -1,109 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the toezeggingen (commitments) and ingekomen-stukken (incoming documents) registers (toezeggingen-ingekomen-stukken). References resolve by slug against existing decidesk seed objects (governance-body/meeting/agenda-item); the nil UUID 00000000-0000-0000-0000-000000000000 is an obvious placeholder where no matching seed object exists (wethouder Person, related motion Decision). One toezegging is seeded past-deadline + non-terminal so the dashboard KPI is non-zero on a fresh install (ADR-016). One IngekomenStuk stays geregistreerd so the placement flow is demoable. A 'Lijst ingekomen stukken' AgendaItem is appended to the agenda-item seed array (deepMergeConfig concatenates list arrays, ADR-037) and attached to the seeded raadsvergadering.", - "objects": { - "toezegging": [ - { - "slug": "toezegging-raadsbrief-jeugdzorg", - "text": "Wethouder Van Dijk zegt toe de raad vóór 1 maart per raadsbrief te informeren over de wachtlijsten jeugdzorg.", - "madeBy": "00000000-0000-0000-0000-000000000000", - "meeting": "raadsvergadering-2025-01-15", - "agendaItem": "begroting-2026-bespreking", - "directedTo": "gemeenteraad-amsterdam", - "deadline": "2026-03-01", - "lifecycle": "open", - "publicationDate": "2026-01-20T09:00:00Z" - }, - { - "slug": "toezegging-schouw-marktplein", - "text": "Wethouder Pietersen zegt toe binnen zes weken een schouw van het Marktplein te organiseren met de klankbordgroep.", - "madeBy": "00000000-0000-0000-0000-000000000000", - "meeting": "raadsvergadering-2025-01-15", - "agendaItem": "rondvraag", - "directedTo": "gemeenteraad-amsterdam", - "deadline": "2026-05-15", - "lifecycle": "in-execution", - "goal": "goal-amsterdam-klimaatneutraal-2050", - "publicationDate": "2026-02-10T09:00:00Z" - }, - { - "slug": "toezegging-evaluatie-afvalbeleid", - "text": "Het college zegt toe de evaluatie van het afvalbeleid gelijktijdig met de kadernota aan te bieden.", - "madeBy": "00000000-0000-0000-0000-000000000000", - "meeting": "raadsvergadering-2025-01-15", - "directedTo": "gemeenteraad-amsterdam", - "deadline": "2026-06-30", - "lifecycle": "disposed", - "settlementNotes": "Evaluatierapport aangeboden bij kadernota 2026; besproken in commissie Middelen.", - "settlementEvidence": "https://gemeente-voorbeeldingen.nl/raadsbrieven/evaluatie-afvalbeleid-2026.pdf", - "relatedMotion": "00000000-0000-0000-0000-000000000000", - "publicationDate": "2026-02-10T09:00:00Z" - } - ], - "ingekomen-stuk": [ - { - "slug": "brief-verkeersveiligheid-schoolzone", - "title": "Brief inzake verkeersveiligheid schoolzone Lindelaan", - "sender": "J. Jansen", - "senderType": "natural-person", - "receivedAt": "2026-01-12", - "category": "letter-resident", - "routingAdvice": "referred-to-executive-board-for-disposal", - "listAgendaItem": "lijst-ingekomen-stukken-2025-01-15", - "directedTo": "gemeenteraad-amsterdam", - "lifecycle": "routing-determined" - }, - { - "slug": "petitie-behoud-zwembad", - "title": "Petitie behoud zwembad De Plons (1.243 ondertekenaars)", - "sender": "Actiecomité De Plons", - "senderType": "organisation", - "receivedAt": "2026-01-15", - "category": "petition", - "routingAdvice": "include-with-agenda-item", - "targetAgendaItem": "begroting-2026-bespreking", - "listAgendaItem": "lijst-ingekomen-stukken-2025-01-15", - "directedTo": "gemeenteraad-amsterdam", - "lifecycle": "agendised" - }, - { - "slug": "collegestuk-jaarverantwoording", - "title": "Jaarverantwoording kinderopvang 2025", - "sender": "College van B&W", - "senderType": "governingBody", - "receivedAt": "2026-01-18", - "category": "executive-board-paper", - "routingAdvice": "noted-for-information", - "listAgendaItem": "lijst-ingekomen-stukken-2025-01-15", - "directedTo": "gemeenteraad-amsterdam", - "lifecycle": "routing-determined" - }, - { - "slug": "uitnodiging-veiligheidsregio", - "title": "Uitnodiging werkbezoek Veiligheidsregio", - "sender": "Veiligheidsregio Midden-Nederland", - "senderType": "governingBody", - "receivedAt": "2026-01-19", - "category": "invitation", - "routingAdvice": "noted-for-information", - "directedTo": "gemeenteraad-amsterdam", - "lifecycle": "registered" - } - ], - "agenda-item": [ - { - "slug": "lijst-ingekomen-stukken-2025-01-15", - "title": "Lijst ingekomen stukken", - "itemType": "decision", - "orderNumber": 5, - "estimatedDuration": 10, - "description": "Hamerstuk-verzamelagendapunt voor de lijst ingekomen stukken; de griffie-routeringsadviezen worden en bloc bekrachtigd via de hamerstuk-flow (agenda-live-management REQ-LIV-003). AgendaItem draagt geen tag-veld, zodat 'hamerstuk' hier conventioneel via itemType 'decision' + deze omschrijving is vastgelegd.", - "meeting": "raadsvergadering-2025-01-15" - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/46-urgency-policy.json b/lib/Settings/register.d/46-urgency-policy.json index 6eddfbae2..fb94ccdf2 100644 --- a/lib/Settings/register.d/46-urgency-policy.json +++ b/lib/Settings/register.d/46-urgency-policy.json @@ -1,193 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Urgent-decision-procedure register fragment (ADR-037 additive pattern; OpenSpec change urgent-decision-procedure). Declarative core ONLY: additive urgency fields on the existing Decision schema (isUrgent, urgencyReason, urgencyDeclaredBy, urgencyDeclaredAt) plus the awaitingRatification derivation and two notification rules, additive shortened-notice deviation fields on Meeting, and a per-template urgencyPolicy object on ProcessTemplate. The urgency-trigger guard (who may set isUrgent), ratification-stage orchestration, expedited-round mechanics, and the declare/banner/badge/KPI UI are IMPERATIVE and live in the change's Service/Controller/Vue tasks (design.md seams A/B + Task 7) — out of this declarative fragment. Seeds here are two urgency-enabled CUSTOM process templates (municipal + corporate), because the built-in templates in 43-process-config-v1.json are read-only (design D5). NOTE (app-wide limitation, consistent with sibling fragments 45/54/55): relation refs stored as slugs (urgencyPolicy.ratifyingBody -> governance-body) may not resolve on detail pages until the register import maps them to UUIDs.", - "objects": { - "process-template": [ - { - "slug": "municipal-council-urgent", - "name": "Municipal Council (urgency-enabled)", - "description": "Municipal council (gemeenteraad) process template with the urgent-decision procedure enabled: college spoedbesluit routed to a mandatory ratification stage at the next regular raadsvergadering (design seed table, municipal column).", - "context": "legislative", - "builtIn": false, - "initialState": "draft", - "stateMachine": { - "states": [ - { - "name": "draft" - }, - { - "name": "proposed" - }, - { - "name": "deliberating" - }, - { - "name": "voting" - }, - { - "name": "decided" - }, - { - "name": "enacted" - }, - { - "name": "archived" - } - ], - "transitions": [ - { - "name": "propose", - "from": "draft", - "to": "proposed" - }, - { - "name": "deliberate", - "from": "proposed", - "to": "deliberating" - }, - { - "name": "openVoting", - "from": "deliberating", - "to": "voting", - "chairOnly": true, - "guards": [ - "quorum_met", - "all_amendments_resolved" - ] - }, - { - "name": "decide", - "from": "voting", - "to": "decided", - "chairOnly": true - }, - { - "name": "enact", - "from": "decided", - "to": "enacted" - }, - { - "name": "archive", - "from": "enacted", - "to": "archived" - } - ] - }, - "votingRule": { - "voteThreshold": "simple-majority", - "abstentionHandling": "exclude", - "tieBreakRule": "rejected" - }, - "quorumRequired": true, - "quorumRule": "More than half of the seats occupied (Gemeentewet art. 20)", - "allowDecideWithoutVote": false, - "urgencyPolicy": { - "allowedTriggerRoles": [ - "chair" - ], - "minimumNoticeFloorHours": 24, - "responseDeadlineHours": { - "min": 12, - "max": 96 - }, - "ratificationRequired": true, - "ratifyingBody": "gemeenteraad-amsterdam" - } - }, - { - "slug": "corporate-board-urgent", - "name": "Corporate Board (urgency-enabled)", - "description": "Corporate management board (RvB) process template with the urgent-decision procedure enabled: urgent resolution decided via an expedited 24h written round, ratified by the Raad van Commissarissen (design seed table, corporate column).", - "context": "corporate", - "builtIn": false, - "initialState": "draft", - "stateMachine": { - "states": [ - { - "name": "draft" - }, - { - "name": "proposed" - }, - { - "name": "deliberating" - }, - { - "name": "voting" - }, - { - "name": "decided" - }, - { - "name": "enacted" - }, - { - "name": "archived" - } - ], - "transitions": [ - { - "name": "propose", - "from": "draft", - "to": "proposed" - }, - { - "name": "deliberate", - "from": "proposed", - "to": "deliberating" - }, - { - "name": "openVoting", - "from": "deliberating", - "to": "voting", - "chairOnly": true, - "guards": [ - "quorum_met" - ] - }, - { - "name": "decide", - "from": "voting", - "to": "decided" - }, - { - "name": "enact", - "from": "decided", - "to": "enacted" - }, - { - "name": "archive", - "from": "enacted", - "to": "archived" - } - ] - }, - "votingRule": { - "voteThreshold": "simple-majority", - "abstentionHandling": "exclude", - "tieBreakRule": "chair-decides" - }, - "quorumRequired": true, - "quorumRule": "Quorum per the articles of association", - "allowDecideWithoutVote": false, - "urgencyPolicy": { - "allowedTriggerRoles": [ - "chair", - "secretary" - ], - "minimumNoticeFloorHours": 12, - "responseDeadlineHours": { - "min": 4, - "max": 72 - }, - "ratificationRequired": true, - "ratifyingBody": "raad-van-commissarissen-acme-bv" - } - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/47-works-council-consultation.json b/lib/Settings/register.d/47-works-council-consultation.json index c38acc9d8..9dd625b0e 100644 --- a/lib/Settings/register.d/47-works-council-consultation.json +++ b/lib/Settings/register.d/47-works-council-consultation.json @@ -1,58 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the works-council-consultation capability (WOR-trajecten: adviesaanvraag art. 25 / instemmingsverzoek art. 27). One schema: ConsultationRequest (slug consultation-request). References resolve by slug against existing decidesk base seed objects (governance-body gemeenteraad-amsterdam, meeting raadsvergadering-2025-01-15, agenda-item begroting-2026-bespreking); the nil UUID 00000000-0000-0000-0000-000000000000 is an obvious placeholder where no matching seed object exists (the bestuurder Person M. van den Berg, the constituency-consultation raadpleging, the linked Decision). DEFERRED (design D2, out of declarative-core scope): a seeded ondernemingsraad governance-body with bodyType=works-council — a fragment cannot extend the base GovernanceBody enum, so the works-council enum value is a one-line additive edit to decidesk_register.json landed separately; until then these trajecten reference the existing gemeenteraad-amsterdam body as a resolvable demonstrable placeholder rather than a non-validatable works-council body. Object 1 (adviesaanvraag-reorganisatie-logistiek) is seeded non-terminal (overlegvergadering) with requestedResponseDate in the past so both dashboard KPIs are non-zero on a fresh install (ADR-016). Object 3 (adviesaanvraag-outsourcing-ict) exercises the full flow including the derived art. 25 lid 6 opschortingstermijn (afwijkend besluit). NOTE (app-wide limitation): relation refs stored as slugs do not resolve on detail pages yet — acceptable for now, consistent with the toezeggingen/constituency seed style.", - "objects": { - "consultation-request": [ - { - "slug": "adviesaanvraag-reorganisatie-logistiek", - "type": "adviceRequest", - "worArticle": "art. 25 lid 1 sub d WOR", - "subject": "Voorgenomen reorganisatie afdeling logistiek (inkrimping 12 fte)", - "director": "00000000-0000-0000-0000-000000000000", - "governanceBody": "gemeenteraad-amsterdam", - "receivedDate": "2026-05-12", - "requestedResponseDate": "2026-06-30", - "consultationMeeting": "raadsvergadering-2025-01-15", - "agendaItem": "begroting-2026-bespreking", - "lifecycle": "consultationMeeting" - }, - { - "slug": "instemmingsverzoek-werktijdenregeling", - "type": "consent-request", - "worArticle": "art. 27 lid 1 sub b WOR", - "subject": "Wijziging werktijdenregeling: invoering zelfroosteren productie", - "director": "00000000-0000-0000-0000-000000000000", - "governanceBody": "gemeenteraad-amsterdam", - "receivedDate": "2026-06-02", - "requestedResponseDate": "2026-08-15", - "constituencyConsultation": "00000000-0000-0000-0000-000000000000", - "lifecycle": "constituencyConsultation" - }, - { - "slug": "adviesaanvraag-outsourcing-ict", - "type": "adviceRequest", - "worArticle": "art. 25 lid 1 sub n WOR", - "subject": "Uitbesteding ICT-beheer aan externe dienstverlener", - "director": "00000000-0000-0000-0000-000000000000", - "governanceBody": "gemeenteraad-amsterdam", - "receivedDate": "2026-01-15", - "requestedResponseDate": "2026-03-01", - "consultationMeeting": "raadsvergadering-2025-01-15", - "agendaItem": "begroting-2026-bespreking", - "responseOutcome": "advice-with-conditions", - "responseText": "De OR adviseert positief onder voorwaarde van een sociaal plan en een evaluatiemoment na 12 maanden.", - "responseDate": "2026-02-24", - "relatedDecision": "00000000-0000-0000-0000-000000000000", - "decisionOutcome": "contrary-to-advice", - "decisionText": "Bestuurder besluit tot uitbesteding zonder evaluatiemoment; sociaal plan wordt overgenomen.", - "decisionDate": "2026-03-10", - "suspensionTo": "2026-04-10", - "lifecycle": "completed" - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { @@ -90,20 +38,62 @@ "withdrawn" ], "transitions": [ - { "from": "received", "to": "in-progress" }, - { "from": "received", "to": "withdrawn" }, - { "from": "in-progress", "to": "constituencyConsultation" }, - { "from": "in-progress", "to": "consultationMeeting" }, - { "from": "in-progress", "to": "withdrawn" }, - { "from": "constituencyConsultation", "to": "consultationMeeting" }, - { "from": "constituencyConsultation", "to": "withdrawn" }, - { "from": "consultationMeeting", "to": "adopted" }, - { "from": "consultationMeeting", "to": "in-progress" }, - { "from": "consultationMeeting", "to": "withdrawn" }, - { "from": "adopted", "to": "sent" }, - { "from": "adopted", "to": "withdrawn" }, - { "from": "sent", "to": "decision-received" }, - { "from": "decision-received", "to": "completed" } + { + "from": "received", + "to": "in-progress" + }, + { + "from": "received", + "to": "withdrawn" + }, + { + "from": "in-progress", + "to": "constituencyConsultation" + }, + { + "from": "in-progress", + "to": "consultationMeeting" + }, + { + "from": "in-progress", + "to": "withdrawn" + }, + { + "from": "constituencyConsultation", + "to": "consultationMeeting" + }, + { + "from": "constituencyConsultation", + "to": "withdrawn" + }, + { + "from": "consultationMeeting", + "to": "adopted" + }, + { + "from": "consultationMeeting", + "to": "in-progress" + }, + { + "from": "consultationMeeting", + "to": "withdrawn" + }, + { + "from": "adopted", + "to": "sent" + }, + { + "from": "adopted", + "to": "withdrawn" + }, + { + "from": "sent", + "to": "decision-received" + }, + { + "from": "decision-received", + "to": "completed" + } ], "_note": "Declarative guarded transition map (ADR-031, REQ-WCC-002). Canonical dialect verbatim (keyword 'initial', never 'initialState'/'states'-only/'default'). ontvangen -> in-behandeling -> (achterbanraadpleging) -> overlegvergadering -> vastgesteld -> verzonden -> besluit-ontvangen -> afgerond. achterbanraadpleging is an optional step (in-behandeling goes to either achterbanraadpleging or directly to overlegvergadering; achterbanraadpleging -> overlegvergadering). overlegvergadering -> in-behandeling allows repeat overleg rounds. ingetrokken is reachable from every non-terminal state before verzonden (ontvangen/in-behandeling/achterbanraadpleging/overlegvergadering/vastgesteld) and, with afgerond, is terminal. No app-side state machine." }, diff --git a/lib/Settings/register.d/48-constituency-consultation.json b/lib/Settings/register.d/48-constituency-consultation.json index 108959bde..0e2c912ae 100644 --- a/lib/Settings/register.d/48-constituency-consultation.json +++ b/lib/Settings/register.d/48-constituency-consultation.json @@ -1,96 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the constituency-consultation capability (achterbanraadpleging / ledenraadpleging). Two schemas: MemberConsultation (slug member-consultation) and MemberConsultationResponse (slug member-consultation-response). References resolve by slug against existing decidesk seed objects (governance-body gemeenteraad-amsterdam; agenda-item begroting-2026-bespreking / rondvraag) or against same-fragment consultation slugs; the nil UUID 00000000-0000-0000-0000-000000000000 is an obvious placeholder where no matching seed object exists (the ALV/vereniging body, the linked Decision). NOTE (app-wide limitation): relation refs stored as slugs do not resolve on detail pages yet — acceptable for now, consistent with the toezeggingen seed style. One consultation is seeded 'open' (raadpleging-fractie-parkeervisie) so the respond surface and closing-soon path are demoable on a fresh install; one is seeded 'verwerkt' with a results summary (achterban-or-thuiswerkregeling) so the meeting-context 'Raadpleging (niet-bindend)' section is non-empty on install (ADR-016). Two responses back the open object and one backs the verwerkt summary.", - "objects": { - "member-consultation": [ - { - "slug": "raadpleging-fractie-parkeervisie", - "question": "Steunt de fractie het raadsvoorstel Parkeervisie 2026–2030 in de huidige vorm?", - "description": "Niet-bindende peiling ter voorbereiding op de raadsvergadering van 12 maart.", - "responseType": "single-choice", - "choiceOptions": [ - "Voor", - "Tegen", - "Voor, mits aangepast" - ], - "audienceType": "politicalGroup", - "audienceBody": "gemeenteraad-amsterdam", - "audienceParty": "Groen Voorbeeldingen", - "agendaItem": "begroting-2026-bespreking", - "opensAt": "2026-02-20T09:00:00Z", - "closesAt": "2026-03-10T17:00:00Z", - "anonymousResponses": false, - "lifecycle": "open" - }, - { - "slug": "ledenraadpleging-alv-contributie", - "question": "Welke contributieverhoging heeft uw voorkeur voor 2027?", - "description": "Peiling onder de leden ter voorbereiding op de ALV; het bestuur legt het definitieve voorstel voor aan de vergadering.", - "responseType": "multi-choice", - "choiceOptions": [ - "Geen verhoging", - "+2%", - "+5%", - "Gedifferentieerd naar leeftijd" - ], - "audienceType": "body-members", - "audienceBody": "00000000-0000-0000-0000-000000000000", - "agendaItem": "rondvraag", - "opensAt": "2026-03-01T09:00:00Z", - "closesAt": "2026-04-01T17:00:00Z", - "anonymousResponses": true, - "lifecycle": "draft" - }, - { - "slug": "achterban-or-thuiswerkregeling", - "question": "Wat vindt de achterban van de voorgestelde thuiswerkregeling (instemmingsaanvraag art. 27 WOR)?", - "description": "Informele raadpleging van de achterban vóór het OR-besluit over de instemmingsaanvraag.", - "responseType": "open-text", - "audienceType": "nc-group", - "audienceGroup": "or-achterban-acme", - "decision": "00000000-0000-0000-0000-000000000000", - "opensAt": "2026-02-01T09:00:00Z", - "closesAt": "2026-02-15T17:00:00Z", - "anonymousResponses": true, - "lifecycle": "processed", - "results": { - "audienceSize": 12, - "responseCount": 9, - "openTextDigest": "Meerderheid positief; zorgen over bereikbaarheid van de servicedesk en over ongelijkheid tussen kantoor- en productiefuncties." - } - } - ], - "member-consultation-response": [ - { - "slug": "respons-parkeervisie-lid-1", - "consultation": "raadpleging-fractie-parkeervisie", - "respondentId": "jvandenberg", - "choices": [ - "Voor, mits aangepast" - ], - "openText": "Mits de parkeernorm voor de binnenstad wordt verlaagd.", - "submittedAt": "2026-02-21T10:15:00Z" - }, - { - "slug": "respons-parkeervisie-lid-2", - "consultation": "raadpleging-fractie-parkeervisie", - "respondentId": "mjansen", - "choices": [ - "Tegen" - ], - "submittedAt": "2026-02-22T08:40:00Z" - }, - { - "slug": "respons-or-achterban-1", - "consultation": "achterban-or-thuiswerkregeling", - "respondentId": "pdevries", - "openText": "Positief, maar de regeling moet ook voor de productieploegen een alternatief bieden.", - "submittedAt": "2026-02-03T12:05:00Z" - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/49-vragenuur-interpellatie.json b/lib/Settings/register.d/49-vragenuur-interpellatie.json index b3ac7fd8d..430f50800 100644 --- a/lib/Settings/register.d/49-vragenuur-interpellatie.json +++ b/lib/Settings/register.d/49-vragenuur-interpellatie.json @@ -1,169 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the vragenuur (oral questions), interpellatie (interpellation requests) and per-body vragenuur-configuratie registers (vragenuur-interpellatie). References resolve by slug against existing decidesk seed objects (governance-body gemeenteraad-amsterdam, meeting raadsvergadering-2025-01-15, and the toezegging toezegging-raadsbrief-jeugdzorg from the toezeggingen-ingekomen-stukken sibling fragment 45); the nil UUID 00000000-0000-0000-0000-000000000000 is an obvious placeholder where no matching seed object exists (raadslid/wethouder Person, and the SchriftelijkeVraag/Fractie references owned by the not-yet-seeded fractievoorzitter-fractie-koppeling change — hard depends_on, design D6). Three AgendaItems are appended to the agenda-item seed array (deepMergeConfig concatenates list arrays, ADR-037): one 'Vragenuur' item on the seeded raadsvergadering so scheduling is demoable on install, plus two dedicated interpellation agenda items for the behandeld/geagendeerd interpellatieverzoeken (ADR-016 testability). MondelingeVraag mv-wachtlijsten-jeugdzorg is seeded beantwoord + escalated from a written question (bronSchriftelijkeVraag placeholder) with a real vervolgToezegging so the full answer-with-commitment path is visible; mv-sluiting-zwembad stays ingediend so the admission action is demoable; mv-opvang-statushouders shows a stored afwijzingsReden. Interpellatieverzoek int-veiligheid-stationsgebied is behandeld (threshold met), int-jaarrekening-grondbedrijf ingediend (below threshold), int-subsidie-cultuurhuis geagendeerd.", - "objects": { - "vragenuur-configuratie": [ - { - "slug": "vragenuur-configuratie-gemeenteraad", - "governanceBody": "gemeenteraad-amsterdam", - "submissionPeriodHours": 24, - "interpellationSupportThresholdType": "fraction", - "interpellationSupportThresholdValue": 0.2 - } - ], - "mondelinge-vraag": [ - { - "slug": "mv-wachtlijsten-jeugdzorg", - "questionNumber": "MV-2026-001", - "subject": "Wachtlijsten jeugdzorg na aanbesteding", - "rationale": "Na de recente aanbesteding jeugdhulp bereiken de fractie signalen van oplopende wachttijden. Graag een toelichting van de portefeuillehouder op de actuele stand en de te nemen maatregelen.", - "submitter": "00000000-0000-0000-0000-000000000000", - "politicalGroup": "00000000-0000-0000-0000-000000000000", - "portfolioHolder": "00000000-0000-0000-0000-000000000000", - "governanceBody": "gemeenteraad-amsterdam", - "targetMeeting": "raadsvergadering-2025-01-15", - "questionHourAgendaItem": "vragenuur-2025-01-15", - "sortOrder": 1, - "lifecycle": "answered", - "answerSummary": "Wethouder erkent oplopende wachttijden; raadsbrief met plan van aanpak toegezegd vóór 1 maart.", - "answeredBy": "00000000-0000-0000-0000-000000000000", - "followUpCommitment": "toezegging-raadsbrief-jeugdzorg", - "sourceWrittenQuestion": "00000000-0000-0000-0000-000000000000" - }, - { - "slug": "mv-verkeersveiligheid-lindelaan", - "questionNumber": "MV-2026-002", - "subject": "Verkeersveiligheid schoolzone Lindelaan", - "rationale": "Ouders melden onveilige situaties tijdens de spits bij de schoolzone Lindelaan. Welke korte-termijnmaatregelen ziet het college?", - "submitter": "00000000-0000-0000-0000-000000000000", - "politicalGroup": "00000000-0000-0000-0000-000000000000", - "portfolioHolder": "00000000-0000-0000-0000-000000000000", - "governanceBody": "gemeenteraad-amsterdam", - "targetMeeting": "raadsvergadering-2025-01-15", - "questionHourAgendaItem": "vragenuur-2025-01-15", - "sortOrder": 2, - "lifecycle": "scheduled" - }, - { - "slug": "mv-sluiting-zwembad", - "questionNumber": "MV-2026-003", - "subject": "Voorgenomen sluiting zwembad De Plons", - "rationale": "In de media wordt gesproken over een voorgenomen sluiting van zwembad De Plons. Klopt dit en is de raad hierover tijdig geïnformeerd?", - "submitter": "00000000-0000-0000-0000-000000000000", - "politicalGroup": "00000000-0000-0000-0000-000000000000", - "portfolioHolder": "00000000-0000-0000-0000-000000000000", - "governanceBody": "gemeenteraad-amsterdam", - "targetMeeting": "raadsvergadering-2025-01-15", - "lifecycle": "submitted" - }, - { - "slug": "mv-opvang-statushouders", - "questionNumber": "MV-2026-004", - "subject": "Opvangcapaciteit statushouders Q3", - "rationale": "Graag inzicht in de opvangcapaciteit voor statushouders in het derde kwartaal en de gevolgen voor de taakstelling.", - "submitter": "00000000-0000-0000-0000-000000000000", - "politicalGroup": "00000000-0000-0000-0000-000000000000", - "portfolioHolder": "00000000-0000-0000-0000-000000000000", - "governanceBody": "gemeenteraad-amsterdam", - "targetMeeting": "raadsvergadering-2025-01-15", - "lifecycle": "rejected", - "rejectionReason": "Betreft een individuele casus, geen algemeen belang" - } - ], - "interpellatieverzoek": [ - { - "slug": "int-veiligheid-stationsgebied", - "requestNumber": "INT-2026-001", - "subject": "Veiligheid stationsgebied", - "questions": "1. Sinds wanneer was het college bekend met de toename van incidenten in het stationsgebied? 2. Welke maatregelen zijn getroffen en waarom is de raad hierover niet eerder geïnformeerd?", - "rationale": "De aanhoudende onveiligheid in het stationsgebied rechtvaardigt een interpellatiedebat buiten de orde van de dag.", - "requester": "00000000-0000-0000-0000-000000000000", - "politicalGroup": "00000000-0000-0000-0000-000000000000", - "portfolioHolder": "00000000-0000-0000-0000-000000000000", - "governanceBody": "gemeenteraad-amsterdam", - "steunbetuigingen": [ - "00000000-0000-0000-0000-000000000000", - "00000000-0000-0000-0000-000000000000", - "00000000-0000-0000-0000-000000000000", - "00000000-0000-0000-0000-000000000000" - ], - "lifecycle": "handled", - "councilResolutionDate": "2026-05-12", - "behandeldIn": "raadsvergadering-2025-01-15", - "agendaItem": "interpellatie-stationsgebied-2025", - "handlingMinutes": "Interpellatiedebat gevoerd; wethouder zegt extern onderzoek toe naar de veiligheidssituatie en informeert de raad per raadsbrief voor het zomerreces." - }, - { - "slug": "int-jaarrekening-grondbedrijf", - "requestNumber": "INT-2026-002", - "subject": "Tekorten jaarrekening grondbedrijf", - "questions": "1. Waarom is de raad niet geïnformeerd over de tekorten in het grondbedrijf? 2. Welke gevolgen heeft dit voor de meerjarenbegroting?", - "rationale": "De omvang van de tekorten en het uitblijven van informatie aan de raad vragen om een interpellatie.", - "requester": "00000000-0000-0000-0000-000000000000", - "politicalGroup": "00000000-0000-0000-0000-000000000000", - "portfolioHolder": "00000000-0000-0000-0000-000000000000", - "governanceBody": "gemeenteraad-amsterdam", - "steunbetuigingen": [ - "00000000-0000-0000-0000-000000000000", - "00000000-0000-0000-0000-000000000000" - ], - "lifecycle": "submitted" - }, - { - "slug": "int-subsidie-cultuurhuis", - "requestNumber": "INT-2026-003", - "subject": "Subsidieverlening cultuurhuis", - "questions": "1. Op welke grond is de subsidie aan het cultuurhuis verhoogd? 2. Voldoet de verhoging aan het geldende subsidiekader?", - "rationale": "De onderbouwing van de subsidieverhoging is voor de raad onvoldoende inzichtelijk.", - "requester": "00000000-0000-0000-0000-000000000000", - "politicalGroup": "00000000-0000-0000-0000-000000000000", - "portfolioHolder": "00000000-0000-0000-0000-000000000000", - "governanceBody": "gemeenteraad-amsterdam", - "steunbetuigingen": [ - "00000000-0000-0000-0000-000000000000", - "00000000-0000-0000-0000-000000000000", - "00000000-0000-0000-0000-000000000000", - "00000000-0000-0000-0000-000000000000", - "00000000-0000-0000-0000-000000000000" - ], - "lifecycle": "agendised", - "councilResolutionDate": "2026-06-30", - "behandeldIn": "raadsvergadering-2025-01-15", - "agendaItem": "interpellatie-cultuurhuis-2025-01-15" - } - ], - "agenda-item": [ - { - "slug": "vragenuur-2025-01-15", - "title": "Vragenuur", - "itemType": "discussion", - "orderNumber": 6, - "estimatedDuration": 30, - "description": "Vragenuur van de raad (Reglement van Orde): raadsleden stellen mondelinge vragen aan de portefeuillehouders. Toegelaten mondelinge vragen worden op dit agendapunt ingepland (vragenuur-interpellatie REQ-VRI-004); de spreektijdklok blijft bij digital-meetings-and-recurrence REQ-STM. AgendaItem draagt geen tag-veld; 'vragenuur' is hier conventioneel via itemType 'discussion' + deze omschrijving vastgelegd.", - "meeting": "raadsvergadering-2025-01-15" - }, - { - "slug": "interpellatie-stationsgebied-2025", - "title": "Interpellatie: veiligheid stationsgebied", - "itemType": "discussion", - "orderNumber": 7, - "estimatedDuration": 45, - "description": "Eigen agendapunt voor het toegelaten interpellatieverzoek int-veiligheid-stationsgebied (vragenuur-interpellatie REQ-VRI-012); een interpellatie krijgt een eigen agendapunt, nooit samengevoegd met het vragenuur.", - "meeting": "raadsvergadering-2025-01-15" - }, - { - "slug": "interpellatie-cultuurhuis-2025-01-15", - "title": "Interpellatie: subsidieverlening cultuurhuis", - "itemType": "discussion", - "orderNumber": 8, - "estimatedDuration": 45, - "description": "Eigen agendapunt voor het geagendeerde interpellatieverzoek int-subsidie-cultuurhuis (vragenuur-interpellatie REQ-VRI-012).", - "meeting": "raadsvergadering-2025-01-15" - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { @@ -335,7 +172,7 @@ "_note": "Rejection notification to the indiener including the afwijzingsReden (REQ-VRI-007). updated-trigger filtered on lifecycle afgewezen." }, "mvIngepland": { - "_note": "No `from` here: `scheduled` is reachable from both `admitted` and `not-handled`, and the updated-condition grammar takes a single `from`. Without it the rule fires on any update while lifecycle is already `scheduled`, which is still far narrower than the ignored `filter` it replaces (that fired on EVERY update). Tighten once the grammar accepts a from-set.", + "_note": "Scheduling notification to the indiener and portefeuillehouder (REQ-VRI-007). updated-trigger filtered on lifecycle ingepland; the target meeting date travels via the object's targetMeeting reference.", "trigger": { "type": "updated", "condition": { @@ -363,8 +200,7 @@ "subject": { "nl": "Mondelinge vraag ingepland voor het vragenuur: {{vraagNummer}} — {{onderwerp}}", "en": "Oral question scheduled for the question hour: {{vraagNummer}} — {{onderwerp}}" - }, - "_note": "Scheduling notification to the indiener and portefeuillehouder (REQ-VRI-007). updated-trigger filtered on lifecycle ingepland; the target meeting date travels via the object's targetMeeting reference." + } } }, "required": [ diff --git a/lib/Settings/register.d/50-termijnagenda.json b/lib/Settings/register.d/50-termijnagenda.json index 8859bec5a..8ceecf9a6 100644 --- a/lib/Settings/register.d/50-termijnagenda.json +++ b/lib/Settings/register.d/50-termijnagenda.json @@ -1,85 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the termijnagenda (long-term agenda / LTA) register (change: termijnagenda). References resolve by slug against existing decidesk seed objects (governanceBody gemeenteraad-amsterdam); the nil UUID 00000000-0000-0000-0000-000000000000 is an obvious placeholder where no matching seed object exists (wethouder Person, origin toezegging/motie/decision, realised agenda item/decision). Object 1 (lta-herziening-parkeerbeleid) is seeded past-period + non-terminal (verschoven) + unrealised so the overdue dashboard KPI is non-zero and the board shows a shifted card on a fresh install (ADR-016; design.md Seed Data). Object 5 (lta-verordening-marktgelden) is past-period + terminal (vervallen) with a redenVervallen so the public list shows a withdrawn-worthy item with its reason. Objects grouped by schema slug 'termijnagenda-item' (the OR seedData import path resolves the schema from the object key; no literal @self wrapper — the '@self.*' token only appears inside dialect filter expressions, not as a seed envelope).", - "objects": { - "termijnagenda-item": [ - { - "slug": "lta-herziening-parkeerbeleid", - "subject": "Herziening parkeerbeleid binnenstad", - "governanceBody": "gemeenteraad-amsterdam", - "plannedPeriod": "2026-Q2", - "expectedType": "council-proposal", - "ownerType": "executive-board", - "notes": "Voortkomend uit de aangenomen motie parkeerdruk; college bereidt een raadsvoorstel voor.", - "lifecycle": "postponed", - "shiftHistory": [ - { - "van": "2026-Q1", - "toPeriod": "2026-Q2", - "reason": "Wacht op uitkomst parkeeronderzoek regio", - "door": "00000000-0000-0000-0000-000000000000", - "op": "2026-03-15T10:00:00Z" - } - ], - "originMotion": "00000000-0000-0000-0000-000000000000", - "goal": "goal-amsterdam-parkeerbeleid-kwartaal", - "publicationDate": "2026-06-20T09:00:00Z" - }, - { - "slug": "lta-rib-wachtlijsten-jeugdzorg", - "subject": "RIB wachtlijsten jeugdzorg", - "governanceBody": "gemeenteraad-amsterdam", - "plannedPeriod": "2026-11", - "expectedType": "council-information-letter", - "ownerType": "portfolio-holder", - "owner": "00000000-0000-0000-0000-000000000000", - "notes": "Toegezegde raadsinformatiebrief over de aanpak van de wachtlijsten jeugdzorg.", - "lifecycle": "planned", - "shiftHistory": [], - "originCommitment": "00000000-0000-0000-0000-000000000000", - "publicationDate": "2026-06-20T09:00:00Z" - }, - { - "slug": "lta-themabijeenkomst-energietransitie", - "subject": "Themabijeenkomst energietransitie", - "governanceBody": "gemeenteraad-amsterdam", - "plannedPeriod": "2027-Q1", - "expectedType": "theme-session", - "ownerType": "council-registry", - "notes": "Beeldvormende bijeenkomst ter voorbereiding op de warmtevisie.", - "lifecycle": "planned", - "shiftHistory": [], - "publicationDate": "2026-06-20T09:00:00Z" - }, - { - "slug": "lta-kadernota-2027", - "subject": "Kadernota 2027", - "governanceBody": "gemeenteraad-amsterdam", - "plannedPeriod": "2027-Q2", - "expectedType": "budget-document", - "ownerType": "executive-board", - "notes": "Reguliere jaarlijkse kadernota in de P&C-cyclus.", - "lifecycle": "planned", - "shiftHistory": [], - "originDecision": "00000000-0000-0000-0000-000000000000" - }, - { - "slug": "lta-verordening-marktgelden", - "subject": "Actualisatie verordening marktgelden", - "governanceBody": "gemeenteraad-amsterdam", - "plannedPeriod": "2026-Q1", - "expectedType": "council-proposal", - "ownerType": "portfolio-holder", - "owner": "00000000-0000-0000-0000-000000000000", - "lifecycle": "lapsed", - "shiftHistory": [], - "reasonExpired": "Opgegaan in de bredere herziening van de legesverordening", - "publicationDate": "2026-06-20T09:00:00Z" - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/51-raadsinformatiebrieven.json b/lib/Settings/register.d/51-raadsinformatiebrieven.json index c283ba8ac..8a3a22389 100644 --- a/lib/Settings/register.d/51-raadsinformatiebrieven.json +++ b/lib/Settings/register.d/51-raadsinformatiebrieven.json @@ -1,87 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the raadsinformatiebrieven register (RIB / collegebrieven) and its per-RIB technische-vragen Q&A thread (raadsinformatiebrieven). References resolve by slug against existing decidesk seed objects (governance-body gemeenteraad-amsterdam, agenda-item lijst-ingekomen-stukken-2025-01-15 and toezegging toezegging-raadsbrief-jeugdzorg from the toezeggingen-ingekomen-stukken sibling fragment 45); the nil UUID 00000000-0000-0000-0000-000000000000 is an obvious placeholder where no matching seed object exists (wethouder/raadslid Person, related motion Decision). Object rib-2026-012 is geagendeerd + published with an afgedaneToezegging link so the toezegging-evidence and agendering flows are demoable on install (ADR-016); rib-2026-013 stays verzonden + unpublished so the publish flow is demoable; rib-2026-014 is betrokken-bij-behandeling with a relatedMotion so the terminal state and motie link are demoable. Technische vraag tv-rib-2026-012-doorlooptijd is beantwoord + published so the anonymous Q&A path is visible on a fresh install; the two gesteld questions keep the record-answer flow demoable and make the compound-predicate negative case (unanswered is never public) testable against seed.", - "objects": { - "raadsinformatiebrief": [ - { - "slug": "rib-2026-012-wachtlijsten-jeugdzorg", - "number": "RIB-2026-012", - "subject": "Wachtlijsten jeugdzorg: stand van zaken en maatregelen", - "portfolioHolder": "00000000-0000-0000-0000-000000000000", - "category": "toezegging-afdoening", - "sentAt": "2026-02-20", - "directedTo": "gemeenteraad-amsterdam", - "letterDocument": "Decidesk/Gemeenteraad Amsterdam/Raadsinformatiebrieven/RIB-2026-012 Wachtlijsten jeugdzorg.pdf", - "attachments": [ - "Decidesk/Gemeenteraad Amsterdam/Raadsinformatiebrieven/RIB-2026-012 Bijlage rapportage wachtlijsten.pdf" - ], - "agendaItem": "lijst-ingekomen-stukken-2025-01-15", - "settledCommitment": "toezegging-raadsbrief-jeugdzorg", - "lifecycle": "agendised", - "publicationDate": "2026-02-21T09:00:00Z" - }, - { - "slug": "rib-2026-013-energietransitie", - "number": "RIB-2026-013", - "subject": "Voortgang energietransitie gebouwde omgeving", - "portfolioHolder": "00000000-0000-0000-0000-000000000000", - "category": "actieve-informatieplicht", - "sentAt": "2026-03-05", - "directedTo": "gemeenteraad-amsterdam", - "letterDocument": "Decidesk/Gemeenteraad Amsterdam/Raadsinformatiebrieven/RIB-2026-013 Voortgang energietransitie.pdf", - "lifecycle": "sent" - }, - { - "slug": "rib-2026-014-afdoening-motie-fietsveiligheid", - "number": "RIB-2026-014", - "subject": "Afdoening motie Fietsveiligheid schoolroutes", - "portfolioHolder": "00000000-0000-0000-0000-000000000000", - "category": "motie-afdoening", - "sentAt": "2026-03-12", - "directedTo": "gemeenteraad-amsterdam", - "letterDocument": "Decidesk/Gemeenteraad Amsterdam/Raadsinformatiebrieven/RIB-2026-014 Afdoening motie fietsveiligheid.pdf", - "agendaItem": "lijst-ingekomen-stukken-2025-01-15", - "relatedMotion": "00000000-0000-0000-0000-000000000000", - "lifecycle": "involved-in-handling", - "publicationDate": "2026-03-13T09:00:00Z" - } - ], - "technische-vraag": [ - { - "slug": "tv-rib-2026-012-doorlooptijd", - "rib": "rib-2026-012-wachtlijsten-jeugdzorg", - "question": "Hoe verhoudt de genoemde gemiddelde doorlooptijd zich tot de landelijke norm?", - "setBy": "00000000-0000-0000-0000-000000000000", - "politicalGroup": "GroenLinks", - "setOn": "2026-02-24", - "answer": "De doorlooptijd ligt 12% boven de landelijke norm; het plan van aanpak voorziet in een reductie naar de norm binnen twee kwartalen.", - "answeredBy": "Afdeling Sociaal Domein", - "answeredOn": "2026-03-02", - "lifecycle": "answered", - "publicationDate": "2026-03-03T09:00:00Z" - }, - { - "slug": "tv-rib-2026-012-regiocijfers", - "rib": "rib-2026-012-wachtlijsten-jeugdzorg", - "question": "Kunnen de wachtlijstcijfers worden uitgesplitst per regiogemeente?", - "setBy": "00000000-0000-0000-0000-000000000000", - "politicalGroup": "VVD", - "setOn": "2026-02-25", - "lifecycle": "put" - }, - { - "slug": "tv-rib-2026-013-netcapaciteit", - "rib": "rib-2026-013-energietransitie", - "question": "Welke wijken lopen vertraging op door netcapaciteit?", - "setBy": "00000000-0000-0000-0000-000000000000", - "politicalGroup": "D66", - "setOn": "2026-03-08", - "lifecycle": "put" - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/52-pc-cyclus.json b/lib/Settings/register.d/52-pc-cyclus.json index d6b1225ab..7c8f65f48 100644 --- a/lib/Settings/register.d/52-pc-cyclus.json +++ b/lib/Settings/register.d/52-pc-cyclus.json @@ -1,317 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the P&C-cyclus capability (pc-cyclus, fragment 52 / ADR-016). Three schemas: PCCyclus (slug pc-cyclus), CyclusTemplate (slug cyclus-template) and CyclusStap (slug cyclus-stap). Two built-in CyclusTemplate seeds (municipal-pc-cyclus / association-jaarstukken, builtIn true, read-only-but-duplicable, process-configuration pattern). Two PCCyclus objects for execution year 2026 (municipal gemeenteraad + association jaarstukken) and ten generated CyclusStap objects (five per cyclus, generated shape: all fields resolved, sequence in template order). References resolve by slug against existing decidesk seed objects (governance-body gemeenteraad-amsterdam); the nil UUID 00000000-0000-0000-0000-000000000000 is an obvious placeholder where no matching seed object exists (the ALV/vereniging body, the behandelende commissie, the linked AgendaItem and Decision) resolved at import. NOTE (design D4): PCCyclus.year is the EXECUTION year (2026); each step's betreftJaar = year + template subjectYearOffset (kadernota/begroting +1 => 2027, berap 0 => 2026, jaarrekening/jaarstukken/decharge -1 => 2025). The municipal berap-2 step is seeded with an aanleverDeadline in the PAST (2026-07-10) while status stays 'gepland' so the 'P&C-stappen over deadline' dashboard KPI is non-zero on a fresh install. The municipal begroting-2027 step keeps agendaItem empty with a behandelingDatum set so the 'behandeling not yet scheduled' rappel path is demoable. Document-slot files ('Programmabegroting 2027 (concept).pdf', 'Jaarstukken 2025.pdf') are named placeholders resolved to real FileService attachments at import; no app-local file storage. Materialised progress counters (stepCount/completedStepCount/overdueStepCount) are seeded on each PCCyclus so consumers read them without recomputation.", - "objects": { - "cyclus-template": [ - { - "slug": "municipal-pc-cyclus", - "name": "Gemeentelijke P&C-cyclus", - "context": "legislative", - "builtIn": true, - "steps": [ - { - "stepType": "jaarrekening", - "label": "Jaarrekening", - "subjectYearOffset": -1, - "deliveryDeadline": "04-15", - "handlingDate": "07-02", - "documentSlots": [ - { "name": "Jaarrekening", "required": true }, - { "name": "Accountantsverslag", "required": true } - ] - }, - { - "stepType": "berap", - "label": "Eerste bestuursrapportage (berap-1)", - "subjectYearOffset": 0, - "deliveryDeadline": "05-01", - "handlingDate": "06-10", - "documentSlots": [ - { "name": "Bestuursrapportage", "required": true } - ] - }, - { - "stepType": "kadernota", - "label": "Kadernota", - "subjectYearOffset": 1, - "deliveryDeadline": "05-15", - "handlingDate": "07-02", - "documentSlots": [ - { "name": "Kadernota", "required": true } - ] - }, - { - "stepType": "berap", - "label": "Tweede bestuursrapportage (berap-2)", - "subjectYearOffset": 0, - "deliveryDeadline": "09-20", - "handlingDate": "11-04", - "documentSlots": [ - { "name": "Bestuursrapportage", "required": true } - ] - }, - { - "stepType": "begroting", - "label": "Programmabegroting", - "subjectYearOffset": 1, - "deliveryDeadline": "09-15", - "technicalQuestionsStart": "09-16", - "technicalQuestionsEnd": "10-05", - "committeeDate": "10-20", - "handlingDate": "11-05", - "documentSlots": [ - { "name": "Programmabegroting", "required": true }, - { "name": "Aanbiedingsbrief", "required": true }, - { "name": "Beantwoording technische vragen", "required": false } - ] - } - ] - }, - { - "slug": "association-jaarstukken", - "name": "Verenigings-/jaarstukkencyclus", - "context": "association", - "builtIn": true, - "steps": [ - { - "stepType": "jaarstukken", - "label": "Jaarstukken", - "subjectYearOffset": -1, - "deliveryDeadline": "03-01", - "handlingDate": "04-15", - "documentSlots": [ - { "name": "Jaarrekening", "required": true }, - { "name": "Bestuursverslag", "required": true }, - { "name": "Kascommissieverslag", "required": true } - ] - }, - { - "stepType": "decharge", - "label": "Decharge bestuur", - "subjectYearOffset": -1, - "handlingDate": "04-15", - "documentSlots": [] - }, - { - "stepType": "berap", - "label": "Tussenrapportage", - "subjectYearOffset": 0, - "deliveryDeadline": "05-15", - "handlingDate": "06-20", - "documentSlots": [ - { "name": "Tussenrapportage", "required": true } - ] - }, - { - "stepType": "jaarplan", - "label": "Jaarplan", - "subjectYearOffset": 1, - "deliveryDeadline": "10-01", - "handlingDate": "11-25", - "documentSlots": [ - { "name": "Jaarplan", "required": true } - ] - }, - { - "stepType": "begroting", - "label": "Begroting", - "subjectYearOffset": 1, - "deliveryDeadline": "10-01", - "handlingDate": "11-25", - "documentSlots": [ - { "name": "Begroting", "required": true } - ] - } - ] - } - ], - "pc-cyclus": [ - { - "slug": "pc-cyclus-2026-gemeenteraad", - "name": "P&C-cyclus 2026", - "year": 2026, - "governanceBody": "gemeenteraad-amsterdam", - "template": "municipal-pc-cyclus", - "stepCount": 5, - "completedStepCount": 2, - "overdueStepCount": 1 - }, - { - "slug": "jaarcyclus-2026-vereniging", - "name": "Jaarcyclus 2026", - "year": 2026, - "governanceBody": "00000000-0000-0000-0000-000000000000", - "template": "association-jaarstukken", - "stepCount": 5, - "completedStepCount": 0, - "overdueStepCount": 0 - } - ], - "cyclus-stap": [ - { - "slug": "jaarrekening-2025-gemeenteraad", - "cyclus": "pc-cyclus-2026-gemeenteraad", - "sequence": 1, - "stepType": "jaarrekening", - "label": "Jaarrekening", - "concernsYear": 2025, - "deliveryDeadline": "2026-04-15", - "decisionMakingBody": "gemeenteraad-amsterdam", - "handlingDate": "2026-07-02", - "documentSlots": [ - { "name": "Jaarrekening", "required": true, "file": "00000000-0000-0000-0000-000000000000" }, - { "name": "Accountantsverslag", "required": true } - ], - "agendaItem": "00000000-0000-0000-0000-000000000000", - "decision": "00000000-0000-0000-0000-000000000000", - "status": "adopted", - "outcome": "vastgesteld" - }, - { - "slug": "berap-1-2026-gemeenteraad", - "cyclus": "pc-cyclus-2026-gemeenteraad", - "sequence": 2, - "stepType": "berap", - "label": "Eerste bestuursrapportage (berap-1)", - "concernsYear": 2026, - "deliveryDeadline": "2026-05-01", - "decisionMakingBody": "gemeenteraad-amsterdam", - "handlingDate": "2026-06-10", - "documentSlots": [ - { "name": "Bestuursrapportage", "required": true } - ], - "status": "completed" - }, - { - "slug": "kadernota-2027-gemeenteraad", - "cyclus": "pc-cyclus-2026-gemeenteraad", - "sequence": 3, - "stepType": "kadernota", - "label": "Kadernota", - "concernsYear": 2027, - "deliveryDeadline": "2026-05-15", - "decisionMakingBody": "gemeenteraad-amsterdam", - "handlingDate": "2026-07-02", - "documentSlots": [ - { "name": "Kadernota", "required": true } - ], - "agendaItem": "00000000-0000-0000-0000-000000000000", - "status": "in-progress" - }, - { - "slug": "berap-2-2026-gemeenteraad", - "cyclus": "pc-cyclus-2026-gemeenteraad", - "sequence": 4, - "stepType": "berap", - "label": "Tweede bestuursrapportage (berap-2)", - "concernsYear": 2026, - "deliveryDeadline": "2026-07-10", - "decisionMakingBody": "gemeenteraad-amsterdam", - "handlingDate": "2026-11-04", - "documentSlots": [ - { "name": "Bestuursrapportage", "required": true } - ], - "status": "planned" - }, - { - "slug": "begroting-2027-gemeenteraad", - "cyclus": "pc-cyclus-2026-gemeenteraad", - "sequence": 5, - "stepType": "begroting", - "label": "Programmabegroting", - "concernsYear": 2027, - "deliveryDeadline": "2026-09-15", - "technicalQuestionsStart": "2026-09-16", - "technicalQuestionsEnd": "2026-10-05", - "handlingCommittee": "00000000-0000-0000-0000-000000000000", - "committeeDate": "2026-10-20", - "decisionMakingBody": "gemeenteraad-amsterdam", - "handlingDate": "2026-11-05", - "documentSlots": [ - { "name": "Programmabegroting", "required": true, "file": "Programmabegroting 2027 (concept).pdf" }, - { "name": "Aanbiedingsbrief", "required": true }, - { "name": "Beantwoording technische vragen", "required": false } - ], - "status": "planned" - }, - { - "slug": "jaarstukken-2025-vereniging", - "cyclus": "jaarcyclus-2026-vereniging", - "sequence": 1, - "stepType": "jaarstukken", - "label": "Jaarstukken", - "concernsYear": 2025, - "deliveryDeadline": "2026-03-01", - "decisionMakingBody": "00000000-0000-0000-0000-000000000000", - "handlingDate": "2026-04-15", - "documentSlots": [ - { "name": "Jaarrekening", "required": true, "file": "Jaarstukken 2025.pdf" }, - { "name": "Bestuursverslag", "required": true }, - { "name": "Kascommissieverslag", "required": true } - ], - "status": "documents-received" - }, - { - "slug": "decharge-2025-vereniging", - "cyclus": "jaarcyclus-2026-vereniging", - "sequence": 2, - "stepType": "decharge", - "label": "Decharge bestuur", - "concernsYear": 2025, - "decisionMakingBody": "00000000-0000-0000-0000-000000000000", - "handlingDate": "2026-04-15", - "documentSlots": [], - "status": "planned" - }, - { - "slug": "tussenrapportage-2026-vereniging", - "cyclus": "jaarcyclus-2026-vereniging", - "sequence": 3, - "stepType": "berap", - "label": "Tussenrapportage", - "concernsYear": 2026, - "deliveryDeadline": "2026-05-15", - "decisionMakingBody": "00000000-0000-0000-0000-000000000000", - "handlingDate": "2026-06-20", - "documentSlots": [ - { "name": "Tussenrapportage", "required": true } - ], - "status": "planned" - }, - { - "slug": "jaarplan-2027-vereniging", - "cyclus": "jaarcyclus-2026-vereniging", - "sequence": 4, - "stepType": "jaarplan", - "label": "Jaarplan", - "concernsYear": 2027, - "deliveryDeadline": "2026-10-01", - "decisionMakingBody": "00000000-0000-0000-0000-000000000000", - "handlingDate": "2026-11-25", - "documentSlots": [ - { "name": "Jaarplan", "required": true } - ], - "status": "planned" - }, - { - "slug": "begroting-2027-vereniging", - "cyclus": "jaarcyclus-2026-vereniging", - "sequence": 5, - "stepType": "begroting", - "label": "Begroting", - "concernsYear": 2027, - "deliveryDeadline": "2026-10-01", - "decisionMakingBody": "00000000-0000-0000-0000-000000000000", - "handlingDate": "2026-11-25", - "documentSlots": [ - { "name": "Begroting", "required": true } - ], - "status": "planned" - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/53-verordeningenregister.json b/lib/Settings/register.d/53-verordeningenregister.json index cb276130e..4fc3fb6b0 100644 --- a/lib/Settings/register.d/53-verordeningenregister.json +++ b/lib/Settings/register.d/53-verordeningenregister.json @@ -1,107 +1,13 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the verordeningenregister (local regulations register — regeling / regeling-versie / regeling-export-package). References resolve by slug against existing decidesk seed objects (governance-body gemeenteraad-amsterdam and ledenraad-vng from decidesk_register.json); the nil UUID 00000000-0000-0000-0000-000000000000 is an obvious placeholder resolved at import where no matching seed object exists (every vastgesteldDoor wijzigingsbesluit Decision — the DECLARATIVE-CORE change ships no Decision seeds of its own; the two extra wijzigingsbesluiten named in design.md Seed Data are added when the imperative slice lands). Two regelingen carry multi-version chains: afvalstoffenverordening-amsterdam has v1 (vervangen, inwerkingtreding 2024-01-01) → v2 (in-werking, 2025-06-01) so REQ-VOR-004 in-force resolution is demoable across a historical boundary on a fresh install (ADR-016); beleidsregel-terrassen-amsterdam has a single in-werking v1; huishoudelijk-reglement-vng is vastgesteld with a concept v1 dated in the future so the REQ-VOR-007 approaching-inwerkingtreding-without-published-text notification path and the 'draft never leaks' public exclusion are both demonstrable. One regeling-export-package in state ready demonstrates the honest-degradation download path (REQ-VOR-006); its STOP/TPOD build + OpenConnector delivery is the imperative slice, deferred. Objects grouped by schema slug (regeling / regeling-versie / regeling-export-package); the OR seedData import path resolves the schema from the object key.", - "objects": { - "regulation": [ - { - "slug": "afvalstoffenverordening-amsterdam", - "type": "by-law", - "citationTitle": "Afvalstoffenverordening Amsterdam", - "officialTitle": "Verordening op de inzameling en verwerking van huishoudelijke afvalstoffen Amsterdam", - "statutoryBasis": [ - "Gemeentewet art. 149", - "Wet milieubeheer art. 10.23" - ], - "determiningBody": "gemeenteraad-amsterdam", - "cvdrIdentifier": "CVDR641871", - "currentVersionNumber": 2, - "currentEffectiveDate": "2025-06-01", - "status": "in-effect" - }, - { - "slug": "beleidsregel-terrassen-amsterdam", - "type": "policy-rule", - "citationTitle": "Beleidsregel terrassen Amsterdam 2025", - "officialTitle": "Beleidsregel inzake terrasvergunningen Amsterdam 2025", - "statutoryBasis": [ - "APV Amsterdam art. 3.17" - ], - "determiningBody": "gemeenteraad-amsterdam", - "currentVersionNumber": 1, - "currentEffectiveDate": "2025-03-01", - "status": "in-effect" - }, - { - "slug": "huishoudelijk-reglement-vng", - "type": "regulations", - "citationTitle": "Huishoudelijk reglement ledenraad VNG", - "officialTitle": "Huishoudelijk reglement van de ledenraad van de Vereniging van Nederlandse Gemeenten", - "statutoryBasis": [ - "Statuten VNG art. 12" - ], - "determiningBody": "ledenraad-vng", - "status": "adopted" - } - ], - "regeling-versie": [ - { - "slug": "afvalstoffen-v1", - "regulation": "afvalstoffenverordening-amsterdam", - "versionNumber": 1, - "determinedBy": "00000000-0000-0000-0000-000000000000", - "effectiveDate": "2024-01-01", - "notes": "Eerste vaststelling van de Afvalstoffenverordening Amsterdam.", - "status": "replaced" - }, - { - "slug": "afvalstoffen-v2", - "regulation": "afvalstoffenverordening-amsterdam", - "versionNumber": 2, - "determinedBy": "00000000-0000-0000-0000-000000000000", - "effectiveDate": "2025-06-01", - "notes": "Wijziging 2025: gescheiden inzameling GFT-e uitgebreid naar het hele beheergebied.", - "status": "in-effect" - }, - { - "slug": "terrassen-v1", - "regulation": "beleidsregel-terrassen-amsterdam", - "versionNumber": 1, - "determinedBy": "00000000-0000-0000-0000-000000000000", - "effectiveDate": "2025-03-01", - "notes": "Vaststelling beleidsregel terrassen 2025.", - "status": "in-effect" - }, - { - "slug": "hr-vng-v1", - "regulation": "huishoudelijk-reglement-vng", - "versionNumber": 1, - "determinedBy": "00000000-0000-0000-0000-000000000000", - "effectiveDate": "2026-09-01", - "notes": "Concept eerste huishoudelijk reglement; treedt in werking na vaststelling door de ledenraad.", - "status": "draft" - } - ], - "regeling-export-package": [ - { - "slug": "export-afvalstoffen-v2", - "regulation": "afvalstoffenverordening-amsterdam", - "versies": [ - "afvalstoffen-v2" - ], - "sourceSlug": "drop-bekendmakingen", - "status": "ready" - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { "Regeling": { "slug": "regeling", "icon": "ScaleBalance", - "version": "0.1.0", + "version": "0.1.1", "title": "Regeling", "description": "A local regulation (regeling): verordening, beleidsregel, nadere regel, reglement, or externe statuut. Schema.org Legislation, Akoma Ntoso 'act' work level (FRBR work): the stable legal identity that a chain of immutable RegelingVersie expressions hangs off. It carries the citeertitel and officiële titel, the wettelijke grondslag, the vaststellend orgaan (a GovernanceBody), the CVDR identifier assigned by the national register after first publication (stored, never minted — REQ-VOR-001/006), and a declarative status lifecycle (ADR-031). In-werking regelingen are anonymously readable through the OpenRegister published-predicate (public register of regelingen in force, REQ-VOR-005); in-voorbereiding/vastgesteld/vervallen regelingen are not public. The regeling never stores consolidated text — that is an attached document on the RegelingVersie via the OR file abstraction. Publication of the regeling to DROP/CVDR runs through the RegelingExportPackage, whose STOP/TPOD build + OpenConnector delivery is the imperative slice (deferred).", "type": "object", @@ -205,6 +111,20 @@ "$ref": "governance-body", "description": "Reference to the GovernanceBody that adopts the regulation (council, ledenraad, etc.). Required." }, + "status": { + "title": "Status", + "type": "string", + "facetable": true, + "description": "Regulation status, and the field x-openregister-lifecycle on this schema drives (field: status). It was REQUIRED and named by the lifecycle map from the day this fragment shipped, but never declared as a property, so OpenRegister created no magic-table column for it. Measured on a live instance: oc_openregister_table_21_262 (and its two duplicates) carried every other Regeling property and no status column at all, which means the declared in-preparation -> adopted -> in-effect -> lapsed transition map could never advance a regulation and the required field could never be satisfied. Enum mirrors x-openregister-lifecycle.states exactly; RegelingVersie.status is the per-version sibling and carries two extra states (draft, replaced) that a regulation as a whole does not have.", + "enum": [ + "in-preparation", + "adopted", + "in-effect", + "lapsed" + ], + "default": "in-preparation", + "example": "in-effect" + }, "cvdrIdentifier": { "title": "CVDR identifier", "type": "string", diff --git a/lib/Settings/register.d/54-delegatie-mandaatregister.json b/lib/Settings/register.d/54-delegatie-mandaatregister.json index 07a507bdd..5f5145198 100644 --- a/lib/Settings/register.d/54-delegatie-mandaatregister.json +++ b/lib/Settings/register.d/54-delegatie-mandaatregister.json @@ -1,101 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the delegatie- en mandaatregister (bevoegdheidstoedeling). References resolve by slug against existing decidesk seed objects (governance-body gemeenteraad-amsterdam; the parent toedeling for the ondermandaat chain); the nil UUID 00000000-0000-0000-0000-000000000000 is an obvious placeholder resolved at import where no matching seed object exists (the college van B&W GovernanceBody, the seed Person for the machtiging, and every authorizing/revoking Decision — Delegatiebesluit 2026, Algemeen mandaatbesluit 2026, Ondermandaatbesluit Samenleving 2026, Volmachtbesluit inkoop 2026, Machtigingsbesluit Woo 2025, Intrekkingsbesluit machtiging Woo). Five objects (design Seed Data table): a raad→college delegatie, a mandaat with ondermandaatToegestaan true and its published ondermandaat (parentToedeling set, depth 1, geldigTot inside the 60-day rappel window so the expiry notification path is demonstrable on a fresh install, ADR-016), a concept volmacht (unpublished so the publish flow is demoable), and an ingetrokken machtiging traced to a revoking decision that shows live on the public register as ingetrokken.", - "objects": { - "bevoegdheidstoedeling": [ - { - "slug": "delegatie-uitwerkingsplannen", - "type": "delegation", - "delegans": "gemeenteraad-amsterdam", - "delegatarisBody": "00000000-0000-0000-0000-000000000000", - "subject": "Vaststellen van uitwerkingsplannen als bedoeld in art. 3.6 Wro", - "beperkingen": "Uitsluitend binnen door de raad vastgestelde kaders", - "subMandatePermitted": false, - "statutoryBasis": [ - "Awb art. 10:13", - "Wro art. 3.6" - ], - "decision": "00000000-0000-0000-0000-000000000000", - "validFrom": "2026-01-01", - "status": "effective", - "publicationDate": "2026-01-05T09:00:00Z" - }, - { - "slug": "mandaat-subsidies-secretaris", - "type": "mandate", - "delegans": "00000000-0000-0000-0000-000000000000", - "delegateRole": "gemeentesecretaris", - "subject": "Beslissen op subsidieaanvragen tot het genoemde plafond", - "financialCeiling": 25000, - "beperkingen": "Geen subsidies met precedentwerking", - "subMandatePermitted": true, - "statutoryBasis": [ - "Awb art. 10:3", - "Asv 2026 art. 4" - ], - "decision": "00000000-0000-0000-0000-000000000000", - "validFrom": "2026-01-01", - "status": "effective", - "publicationDate": "2026-01-05T09:00:00Z" - }, - { - "slug": "ondermandaat-subsidies-samenleving", - "type": "mandate", - "delegansDescription": "gemeentesecretaris", - "delegateRole": "afdelingshoofd Samenleving", - "subject": "Beslissen op subsidieaanvragen binnen het programma Samenleving", - "financialCeiling": 5000, - "beperkingen": "Uitsluitend reguliere subsidieregelingen", - "subMandatePermitted": false, - "statutoryBasis": [ - "Awb art. 10:9" - ], - "decision": "00000000-0000-0000-0000-000000000000", - "parentAllocation": "mandaat-subsidies-secretaris", - "validFrom": "2026-02-01", - "validTo": "2026-08-15", - "status": "effective", - "publicationDate": "2026-02-05T09:00:00Z" - }, - { - "slug": "volmacht-inkoop-teamleider", - "type": "power-of-attorney", - "delegansDescription": "burgemeester", - "delegateRole": "teamleider Inkoop", - "subject": "Aangaan van privaatrechtelijke rechtshandelingen voor inkoop", - "financialCeiling": 50000, - "beperkingen": "Binnen het vastgestelde inkoopbeleid", - "subMandatePermitted": false, - "statutoryBasis": [ - "BW art. 3:60", - "Gemeentewet art. 171" - ], - "decision": "00000000-0000-0000-0000-000000000000", - "validFrom": "2026-03-01", - "status": "draft" - }, - { - "slug": "machtiging-woo-vertegenwoordiging", - "type": "authorisation", - "delegans": "00000000-0000-0000-0000-000000000000", - "delegateRole": "juridisch adviseur team Recht", - "delegatePerson": "00000000-0000-0000-0000-000000000000", - "subject": "Vertegenwoordiging bij Woo-bezwaarprocedures", - "subMandatePermitted": false, - "statutoryBasis": [ - "Awb art. 10:3" - ], - "decision": "00000000-0000-0000-0000-000000000000", - "validFrom": "2025-01-01", - "validTo": "2026-01-01", - "status": "withdrawn", - "withdrawnBy": "00000000-0000-0000-0000-000000000000", - "publicationDate": "2025-01-10T09:00:00Z" - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/55-governing-documents-register.json b/lib/Settings/register.d/55-governing-documents-register.json index d3f1c5cb7..e90a79da8 100644 --- a/lib/Settings/register.d/55-governing-documents-register.json +++ b/lib/Settings/register.d/55-governing-documents-register.json @@ -1,115 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the governing-documents register (constitutive/internal governing documents — statuten, reglement van orde, splitsingsakte). Objects grouped by schema slug (governing-document, governing-document-versie), plus one new governance-body (vve-parkstaete) and two enacting Decisions merged additively into the existing decision seed set. References resolve by slug against existing decidesk seed objects (governance-body ledenraad-vng and gemeenteraad-amsterdam from decidesk_register.json; the two same-fragment Decisions for the amendment versions' vastgesteldDoor). Chain: statuten-vng carries v1 (vervangen, constitutive — no vastgesteldDoor, notarial-deed metadata documents its origin) → v2 (in-werking, traced to besluit-statutenwijziging-vng-2021) to demonstrate in-force resolution (REQ-GDR-004) and seal-on-effective immutability (REQ-GDR-003); statuten-vng has isPublic=true so the public predicate is demonstrable on a fresh install (REQ-GDR-007). reglement-van-orde-raad-amsterdam has one vastgesteld-by-decision version (rvo-amsterdam-v1, traced to besluit-vaststelling-rvo-amsterdam). splitsingsakte-vve-parkstaete has one constitutive notarial version (no decision link). The statutenwijziging Decision carries a citesGoverningDocuments entry (document statuten-vng, artikel 'art. 20') so the citation UI is demoable on install (REQ-GDR-005). NOTE (app-wide limitation, consistent with sibling fragments 45/54): relation refs stored as slugs may not resolve on detail pages until the register import maps them to UUIDs.", - "objects": { - "governance-body": [ - { - "slug": "vve-parkstaete", - "name": "VvE Parkstaete", - "bodyType": "association", - "domain": "association", - "workflowTemplate": "association", - "votingDefault": "for-against-abstain" - } - ], - "governing-document": [ - { - "slug": "statuten-vng", - "type": "articles-of-association", - "citationTitle": "Statuten Vereniging van Nederlandse Gemeenten", - "description": "Statuten van de vereniging (BW 2:27), constitutief bij notariële akte en gewijzigd bij besluit tot statutenwijziging van de ledenraad.", - "governingBody": "ledenraad-vng", - "isPublic": true, - "status": "in-force" - }, - { - "slug": "reglement-van-orde-raad-amsterdam", - "type": "rules-of-procedure", - "citationTitle": "Reglement van orde gemeenteraad Amsterdam", - "description": "Reglement van orde van de gemeenteraad (Gemeentewet art. 16), vastgesteld bij raadsbesluit.", - "governingBody": "gemeenteraad-amsterdam", - "isPublic": false, - "status": "in-force" - }, - { - "slug": "splitsingsakte-vve-parkstaete", - "type": "deed-of-division", - "citationTitle": "Splitsingsakte VvE Parkstaete", - "description": "Splitsingsakte (BW 5:111), constitutief bij notariële akte; geen verband met een besluit.", - "governingBody": "vve-parkstaete", - "isPublic": false, - "status": "in-force" - } - ], - "governing-document-versie": [ - { - "slug": "statuten-vng-v1", - "document": "statuten-vng", - "versionNumber": 1, - "effectiveDate": "1990-05-01", - "notes": "Constitutieve versie bij oprichting van de vereniging; opgericht bij notariële akte, geen verband met een besluit in Decidiq.", - "deedDate": "1990-04-12", - "notary": "mr. C. van Dam", - "status": "replaced" - }, - { - "slug": "statuten-vng-v2", - "document": "statuten-vng", - "versionNumber": 2, - "determinedBy": "besluit-statutenwijziging-vng-2021", - "effectiveDate": "2022-01-01", - "notes": "Statutenwijziging 2021: aanpassing van de bevoegdheden van de ledenraad (art. 20).", - "deedDate": "2021-12-15", - "notary": "mr. A. de Wit", - "status": "in-effect" - }, - { - "slug": "rvo-amsterdam-v1", - "document": "reglement-van-orde-raad-amsterdam", - "versionNumber": 1, - "determinedBy": "besluit-vaststelling-rvo-amsterdam", - "effectiveDate": "2023-03-01", - "notes": "Vaststelling van het reglement van orde door de gemeenteraad.", - "status": "in-effect" - }, - { - "slug": "splitsingsakte-parkstaete-v1", - "document": "splitsingsakte-vve-parkstaete", - "versionNumber": 1, - "effectiveDate": "2005-06-01", - "notes": "Constitutieve splitsingsakte bij notariële akte; geen verband met een besluit.", - "deedDate": "2005-05-20", - "notary": "mr. B. Jansen", - "status": "in-effect" - } - ], - "decision": [ - { - "slug": "besluit-statutenwijziging-vng-2021", - "decisionType": "resolution", - "title": "Besluit statutenwijziging VNG 2021", - "text": "Besluit van de ledenraad van de Vereniging van Nederlandse Gemeenten tot wijziging van de statuten (BW 2:43), in het bijzonder de bevoegdheden van de ledenraad in art. 20.", - "decisionDate": "2021-12-15", - "outcome": "adopted", - "citesGoverningDocuments": [ - { - "document": "statuten-vng", - "article": "art. 20" - } - ] - }, - { - "slug": "besluit-vaststelling-rvo-amsterdam", - "decisionType": "resolution", - "title": "Besluit vaststelling reglement van orde gemeenteraad Amsterdam", - "text": "Besluit van de gemeenteraad van Amsterdam tot vaststelling van het reglement van orde (Gemeentewet art. 16).", - "decisionDate": "2023-03-01", - "outcome": "adopted" - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/56-shared-governance-bodies.json b/lib/Settings/register.d/56-shared-governance-bodies.json index 9f9490427..05268137b 100644 --- a/lib/Settings/register.d/56-shared-governance-bodies.json +++ b/lib/Settings/register.d/56-shared-governance-bodies.json @@ -1,165 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the shared-governance-bodies capability (gemeenschappelijke regeling per Wgr), modelled on the SED-organisatie pattern: three fictional municipalities (Noorderbrug, Oostwoud, Zuidermeer) share one uitvoeringsorganisatie ('NOZ organisatie'). Objects grouped by schema slug (governance-body [shared-body + three legislative raden, additively appended to the existing governance-body seed set], body-participation, person, membership [two board members demonstrating the new namens provenance], zienswijzeronde, zienswijze). References resolve by slug against same-fragment and existing decidesk seed objects; the nil UUID 00000000-0000-0000-0000-000000000000 is an obvious placeholder where no matching seed object exists (the pc-cyclus begroting CyclusStap and a participant raadsbesluit Decision, both cross-seed and resolved at import). Ronde 2's zienswijze (zienswijze-noorderbrug-wijziging-gr) is left uitstaand so the 'Openstaande zienswijzen' KPI is non-zero on a fresh install (ADR-016); ronde 1 exercises the full flow including verwerking and a niet-ingediend participant; participation weights 2/2/1 make the weighted-roster scenario demonstrable. NOTE (app-wide limitation, consistent with sibling fragments 45/54/55): relation refs stored as slugs may not resolve to UUIDs on detail pages until the register import maps them.", - "objects": { - "governance-body": [ - { - "slug": "bestuur-noz-organisatie", - "name": "Bestuur NOZ organisatie", - "bodyType": "shared-body", - "domain": "municipal", - "workflowTemplate": "legislative" - }, - { - "slug": "gemeenteraad-noorderbrug", - "name": "Gemeenteraad Noorderbrug", - "bodyType": "legislative", - "domain": "municipal", - "workflowTemplate": "legislative" - }, - { - "slug": "gemeenteraad-oostwoud", - "name": "Gemeenteraad Oostwoud", - "bodyType": "legislative", - "domain": "municipal", - "workflowTemplate": "legislative" - }, - { - "slug": "gemeenteraad-zuidermeer", - "name": "Gemeenteraad Zuidermeer", - "bodyType": "legislative", - "domain": "municipal", - "workflowTemplate": "legislative" - } - ], - "body-participation": [ - { - "slug": "deelname-noorderbrug-noz", - "sharedBody": "bestuur-noz-organisatie", - "participant": "gemeenteraad-noorderbrug", - "seats": 2, - "votingWeight": 2, - "accessionDate": "2015-01-01T00:00:00Z", - "label": "Deelnemer per oprichting" - }, - { - "slug": "deelname-oostwoud-noz", - "sharedBody": "bestuur-noz-organisatie", - "participant": "gemeenteraad-oostwoud", - "seats": 2, - "votingWeight": 2, - "accessionDate": "2015-01-01T00:00:00Z", - "label": "Deelnemer per oprichting" - }, - { - "slug": "deelname-zuidermeer-noz", - "sharedBody": "bestuur-noz-organisatie", - "participant": "gemeenteraad-zuidermeer", - "seats": 1, - "votingWeight": 1, - "accessionDate": "2015-01-01T00:00:00Z", - "label": "Deelnemer per oprichting" - } - ], - "person": [ - { - "slug": "persoon-w-van-dam", - "name": "W. van Dam", - "familyName": "van Dam", - "givenName": "W." - }, - { - "slug": "persoon-a-terpstra", - "name": "A. Terpstra", - "familyName": "Terpstra", - "givenName": "A." - } - ], - "membership": [ - { - "slug": "lidmaatschap-van-dam-noz", - "role": "chair", - "person": "persoon-w-van-dam", - "governanceBody": "bestuur-noz-organisatie", - "onBehalfOf": "gemeenteraad-noorderbrug", - "votingWeight": 2, - "startDate": "2018-04-01" - }, - { - "slug": "lidmaatschap-terpstra-noz", - "role": "member", - "person": "persoon-a-terpstra", - "governanceBody": "bestuur-noz-organisatie", - "onBehalfOf": "gemeenteraad-zuidermeer", - "votingWeight": 1, - "startDate": "2018-04-01" - } - ], - "zienswijzeronde": [ - { - "slug": "zienswijzeronde-begroting-2027", - "title": "Zienswijzeronde ontwerpbegroting 2027 NOZ organisatie", - "sharedBody": "bestuur-noz-organisatie", - "subjectType": "draft-budget", - "subjectDescription": "Ontwerpbegroting 2027, aangeboden aan de raden conform art. 35 Wgr.", - "deadline": "2026-06-15", - "cyclusStep": "00000000-0000-0000-0000-000000000000", - "status": "processing" - }, - { - "slug": "zienswijzeronde-wijziging-gr-2026", - "title": "Zienswijzeronde wijziging gemeenschappelijke regeling", - "sharedBody": "bestuur-noz-organisatie", - "subjectType": "amendment-of-arrangement", - "subjectDescription": "Voorstel tot wijziging van de regeling i.v.m. taakuitbreiding vergunningverlening.", - "deadline": "2026-09-30", - "status": "opened" - } - ], - "zienswijze": [ - { - "slug": "zienswijze-noorderbrug-begroting-2027", - "ronde": "zienswijzeronde-begroting-2027", - "participant": "gemeenteraad-noorderbrug", - "deadline": "2026-06-15", - "position": "positive-with-reservations", - "text": "De raad stemt in met de ontwerpbegroting, met de kanttekening dat de indexatie van de gemeentelijke bijdrage maximaal 3% mag bedragen.", - "submittedDate": "2026-06-10T00:00:00Z", - "decision": "00000000-0000-0000-0000-000000000000", - "processing": "partly-adopted", - "processingNotes": "Indexatie verlaagd naar 3,2%; volledige inwilliging niet mogelijk binnen de CAO-ontwikkeling.", - "status": "processed" - }, - { - "slug": "zienswijze-oostwoud-begroting-2027", - "ronde": "zienswijzeronde-begroting-2027", - "participant": "gemeenteraad-oostwoud", - "deadline": "2026-06-15", - "position": "positive", - "text": "De raad stemt zonder opmerkingen in met de ontwerpbegroting 2027.", - "submittedDate": "2026-06-02T00:00:00Z", - "processing": "adopted", - "processingNotes": "Voor kennisgeving aangenomen.", - "status": "processed" - }, - { - "slug": "zienswijze-zuidermeer-begroting-2027", - "ronde": "zienswijzeronde-begroting-2027", - "participant": "gemeenteraad-zuidermeer", - "deadline": "2026-06-15", - "status": "not-submitted" - }, - { - "slug": "zienswijze-noorderbrug-wijziging-gr", - "ronde": "zienswijzeronde-wijziging-gr-2026", - "participant": "gemeenteraad-noorderbrug", - "deadline": "2026-09-30", - "status": "outstanding" - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/57-vve-alv-pack.json b/lib/Settings/register.d/57-vve-alv-pack.json index 4fb8f31f6..2f423d72f 100644 --- a/lib/Settings/register.d/57-vve-alv-pack.json +++ b/lib/Settings/register.d/57-vve-alv-pack.json @@ -1,192 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "VvE ALV statutory pack seed data (planted via OpenRegister x-openregister.seedData path, ADR-016). Three built-in ModelreglementPreset objects (1992/2006/2017) and six built-in VveDecisionTemplate objects ship read-only-but-duplicable exactly like process-configuration's built-ins (builtIn: true). One VveConfiguration (VvE Zeewaarts) binds a body to modelreglement-2017, denominator 10.000, and one splitsingsakte majority override; two KascommissieVerklaring objects demonstrate the goedkeurend and met-voorbehoud verdicts. References resolve by slug against same-fragment seeds (modelreglement-2017) or existing decidesk seeds; the nil UUID 00000000-0000-0000-0000-000000000000 is an obvious placeholder where no matching seed object exists yet (the VvE governance body, the jaarrekening agenda item, and the splitsingsakte governing document registered by the governing-documents-register sibling). Seeded majorities name their modelreglement article and require juridical review before release (proposal Risk 1 / Open Questions).", - "objects": { - "modelreglement-preset": [ - { - "slug": "modelreglement-1992", - "name": "Modelreglement 1992", - "description": "Modelreglement bij splitsing in appartementsrechten, versie 1992. Categoriemajoriteiten en quora per de artikelen van dit modelreglement. Read-only built-in; dupliceer om af te wijken.", - "builtIn": true, - "categoryRules": [ - { - "decisionCategory": "authorisation-above-threshold", - "voteThreshold": "qualified-majority-three-quarters", - "quorumFraction": "2/3", - "article": "MR 1992 art. 38 lid 5" - }, - { - "decisionCategory": "amendment-internal-regulations", - "voteThreshold": "qualified-majority-two-thirds", - "quorumFraction": null, - "article": "MR 1992 art. 44" - }, - { - "decisionCategory": "other", - "voteThreshold": "simple-majority", - "quorumFraction": null, - "article": "MR 1992 hoofdregel gewone meerderheid" - } - ] - }, - { - "slug": "modelreglement-2006", - "name": "Modelreglement 2006", - "description": "Modelreglement bij splitsing in appartementsrechten, versie 2006. Categoriemajoriteiten en quora per de artikelen van dit modelreglement. Read-only built-in; dupliceer om af te wijken.", - "builtIn": true, - "categoryRules": [ - { - "decisionCategory": "authorisation-above-threshold", - "voteThreshold": "qualified-majority-two-thirds", - "quorumFraction": "2/3", - "article": "MR 2006 art. 52 lid 5" - }, - { - "decisionCategory": "amendment-internal-regulations", - "voteThreshold": "qualified-majority-two-thirds", - "quorumFraction": null, - "article": "MR 2006 art. 59" - }, - { - "decisionCategory": "other", - "voteThreshold": "simple-majority", - "quorumFraction": null, - "article": "MR 2006 hoofdregel gewone meerderheid" - } - ] - }, - { - "slug": "modelreglement-2017", - "name": "Modelreglement 2017", - "description": "Modelreglement bij splitsing in appartementsrechten, versie 2017. Categoriemajoriteiten en quora per de artikelen van dit modelreglement. Read-only built-in; dupliceer om af te wijken.", - "builtIn": true, - "categoryRules": [ - { - "decisionCategory": "authorisation-above-threshold", - "voteThreshold": "qualified-majority-two-thirds", - "quorumFraction": "2/3", - "article": "MR 2017 art. 56 lid 5" - }, - { - "decisionCategory": "amendment-internal-regulations", - "voteThreshold": "qualified-majority-two-thirds", - "quorumFraction": null, - "article": "MR 2017 art. 60" - }, - { - "decisionCategory": "other", - "voteThreshold": "simple-majority", - "quorumFraction": null, - "article": "MR 2017 hoofdregel gewone meerderheid" - } - ] - } - ], - "vve-decision-template": [ - { - "slug": "decharge-bestuur", - "name": "Decharge bestuur", - "description": "Decharge van het bestuur over het afgelopen boekjaar door de algemene ledenvergadering.", - "decisionCategory": "discharge", - "proposedText": "De vergadering verleent het bestuur decharge voor het gevoerde beleid en beheer over het boekjaar {boekjaar}, gehoord de verklaring van de kascommissie.", - "builtIn": true, - "defaultVoteThreshold": "simple-majority", - "defaultQuorumFraction": null, - "regulationSource": "BW 2:48/2:49" - }, - { - "slug": "vaststelling-jaarrekening", - "name": "Vaststelling jaarrekening", - "description": "Vaststelling van de jaarrekening (exploitatie- en balansoverzicht) van het afgelopen boekjaar.", - "decisionCategory": "annual-accounts", - "proposedText": "De vergadering stelt de jaarrekening over het boekjaar {boekjaar} vast conform het door het bestuur aangeboden exploitatie- en balansoverzicht.", - "builtIn": true, - "defaultVoteThreshold": "simple-majority", - "defaultQuorumFraction": null, - "regulationSource": "MR 2017 art. 14/15" - }, - { - "slug": "dotatie-reservefonds", - "name": "Dotatie reservefonds", - "description": "Besluit tot dotatie aan het reservefonds voor groot onderhoud.", - "decisionCategory": "reserve-fund-contribution", - "proposedText": "De vergadering besluit over het boekjaar {boekjaar} een bedrag te doteren aan het reservefonds ten behoeve van toekomstig groot onderhoud, conform de MJOP-grondslag.", - "builtIn": true, - "defaultVoteThreshold": "simple-majority", - "defaultQuorumFraction": null, - "regulationSource": "Woningwet reservefonds (BW 5:126)" - }, - { - "slug": "vaststelling-mjop", - "name": "Vaststelling/actualisatie MJOP", - "description": "Vaststelling of actualisatie van het meerjarenonderhoudsplan (MJOP).", - "decisionCategory": "mjop-adoption", - "proposedText": "De vergadering stelt het meerjarenonderhoudsplan (MJOP) {periode} vast, respectievelijk actualiseert het geldende MJOP conform het aangeboden concept.", - "builtIn": true, - "defaultVoteThreshold": "simple-majority", - "defaultQuorumFraction": null, - "regulationSource": "MR 2017 art. 14 (MJOP-grondslag)" - }, - { - "slug": "machtiging-boven-drempel", - "name": "Machtiging bestuur onderhoud boven drempel", - "description": "Machtiging aan het bestuur voor onderhoudsuitgaven boven de in het reglement bepaalde drempel.", - "decisionCategory": "authorisation-above-threshold", - "proposedText": "De vergadering machtigt het bestuur tot het aangaan van de onderhoudsverplichting {omschrijving} voor een bedrag van {bedrag}, welk bedrag de reglementaire drempel overschrijdt.", - "builtIn": true, - "defaultVoteThreshold": "qualified-majority-two-thirds", - "defaultQuorumFraction": "2/3", - "regulationSource": "MR 2017 art. 56 lid 5" - }, - { - "slug": "wijziging-huishoudelijk-reglement", - "name": "Wijziging huishoudelijk reglement", - "description": "Wijziging van het huishoudelijk reglement van de vereniging van eigenaars.", - "decisionCategory": "amendment-internal-regulations", - "proposedText": "De vergadering besluit het huishoudelijk reglement te wijzigen conform het aangeboden voorstel {omschrijving}.", - "builtIn": true, - "defaultVoteThreshold": "qualified-majority-two-thirds", - "defaultQuorumFraction": null, - "regulationSource": "MR 2017 art. 60" - } - ], - "vve-configuration": [ - { - "slug": "vve-zeewaarts-configuratie", - "governanceBody": "00000000-0000-0000-0000-000000000000", - "modelRegulation": "modelreglement-2017", - "fractionDenominator": 10000, - "deedOfDivisionDocument": "00000000-0000-0000-0000-000000000000", - "majorityOverrides": [ - { - "decisionCategory": "amendment-internal-regulations", - "voteThreshold": "qualified-majority-three-quarters", - "quorumFraction": null, - "deedArticle": "splitsingsakte 2019 art. 62" - } - ] - } - ], - "kascommissie-verklaring": [ - { - "slug": "kascommissie-verklaring-2025", - "financialYear": 2025, - "verdict": "approving", - "notes": "Administratie ordelijk; reservefondsdotatie conform MJOP.", - "agendaItem": "00000000-0000-0000-0000-000000000000", - "governanceBody": "00000000-0000-0000-0000-000000000000" - }, - { - "slug": "kascommissie-verklaring-2024", - "financialYear": 2024, - "verdict": "qualified", - "notes": "Voorbehoud: onderhoudsfacturen Q3 ontbraken bij controle.", - "governanceBody": "00000000-0000-0000-0000-000000000000" - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/58-woo-diwoo-publication.json b/lib/Settings/register.d/58-woo-diwoo-publication.json index 0c22f623e..7fec820dd 100644 --- a/lib/Settings/register.d/58-woo-diwoo-publication.json +++ b/lib/Settings/register.d/58-woo-diwoo-publication.json @@ -1,86 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the Woo/DiWoo compliance layer (woo-diwoo-publication, fragment 58, ADR-037). Two pure-config schemas: woo-categorie-mapping (per-publishable-type default TOOI informatiecategorie) and woo-bestuursorgaan (per-governance-body bestuursorgaan TOOI identifier override). These are DECLARATIVE CORE ONLY: the DiWoo payload decoration, the Woo-index sitemap harvest, and the optional OpenConnector LV-Woo push are IMPERATIVE services and ship separately (design D: DiWooMetadataService / WooIndexController / WooIndexConnectorService). Per REQ-WOO-001 a mapping row whose objectType schema is not yet installed (sibling change not landed — motie/toezegging/raadsinformatiebrief/regeling) is inert: it never blocks import, publication, or the coverage report. Woo metadata NEVER blocks lawful publication; gaps are made loud through the coverage KPI (REQ-WOO-005), never by refusing to publish. PLACEHOLDER WARNING: every informatiecategorie value below is an OBVIOUS SHAPE-ONLY PLACEHOLDER (segment c_PLACEHOLDER_...). The implementation task MUST copy the exact concept URI verbatim from the published TOOI waardelijst woo-informatiecategorieen; invented concept ids MUST NOT ship (design 'TOOI URIs are data, never code'; proposal Risk 1). The bestuursorgaan gemeente code is likewise an example to be set to the real instance body id. References resolve by slug against existing decidesk seed objects (governance body gemeenteraad-amsterdam).", - "objects": { - "woo-categorie-mapping": [ - { - "slug": "woo-map-meeting-agenda", - "objectType": "meeting-agenda", - "informatiecategorie": "https://identifier.overheid.nl/tooi/def/thes/kern/c_PLACEHOLDER_vergaderstukken-decentrale-overheden", - "informatiecategorieLabel": "Vergaderstukken decentrale overheden", - "active": true, - "notes": "Meeting agenda payload. PLACEHOLDER informatiecategorie — copy the exact vergaderstukken-decentrale-overheden concept URI verbatim from the published TOOI waardelijst at implementation." - }, - { - "slug": "woo-map-besluitenlijst", - "objectType": "decision-list", - "informatiecategorie": "https://identifier.overheid.nl/tooi/def/thes/kern/c_PLACEHOLDER_vergaderstukken-decentrale-overheden", - "informatiecategorieLabel": "Vergaderstukken decentrale overheden", - "active": true, - "notes": "Generated decision-list document (p2-minutes-and-decisions-core-t1). PLACEHOLDER informatiecategorie — copy verbatim from the published TOOI waardelijst at implementation." - }, - { - "slug": "woo-map-minutes", - "objectType": "minutes", - "informatiecategorie": "https://identifier.overheid.nl/tooi/def/thes/kern/c_PLACEHOLDER_vergaderstukken-decentrale-overheden", - "informatiecategorieLabel": "Vergaderstukken decentrale overheden", - "active": true, - "notes": "ORI Verslag. PLACEHOLDER informatiecategorie — copy verbatim from the published TOOI waardelijst at implementation." - }, - { - "slug": "woo-map-decision", - "objectType": "decision", - "informatiecategorie": "https://identifier.overheid.nl/tooi/def/thes/kern/c_PLACEHOLDER_vergaderstukken-decentrale-overheden", - "informatiecategorieLabel": "Vergaderstukken decentrale overheden", - "active": true, - "notes": "ORI Besluit. PLACEHOLDER informatiecategorie — copy verbatim from the published TOOI waardelijst at implementation." - }, - { - "slug": "woo-map-motie", - "objectType": "motion", - "informatiecategorie": "https://identifier.overheid.nl/tooi/def/thes/kern/c_PLACEHOLDER_vergaderstukken-decentrale-overheden", - "informatiecategorieLabel": "Vergaderstukken decentrale overheden", - "active": true, - "notes": "Inert until the Motie schema (sibling motie-amendement-administratie) lands — REQ-WOO-001. PLACEHOLDER informatiecategorie — copy verbatim at implementation." - }, - { - "slug": "woo-map-toezegging", - "objectType": "commitment", - "informatiecategorie": "https://identifier.overheid.nl/tooi/def/thes/kern/c_PLACEHOLDER_vergaderstukken-decentrale-overheden", - "informatiecategorieLabel": "Vergaderstukken decentrale overheden", - "active": true, - "notes": "Predicate-published (sibling toezeggingen-ingekomen-stukken, fragment 45). PLACEHOLDER informatiecategorie — copy verbatim at implementation." - }, - { - "slug": "woo-map-raadsinformatiebrief", - "objectType": "council-information-letter", - "informatiecategorie": "https://identifier.overheid.nl/tooi/def/thes/kern/c_PLACEHOLDER_vergaderstukken-decentrale-overheden", - "informatiecategorieLabel": "Vergaderstukken decentrale overheden", - "active": true, - "notes": "Predicate-published (sibling raadsinformatiebrieven, fragment 51). PLACEHOLDER informatiecategorie — copy verbatim at implementation." - }, - { - "slug": "woo-map-regeling", - "objectType": "arrangement", - "informatiecategorie": "https://identifier.overheid.nl/tooi/def/thes/kern/c_PLACEHOLDER_wetten-en-algemeen-verbindende-voorschriften", - "informatiecategorieLabel": "Wetten en algemeen verbindende voorschriften", - "active": true, - "notes": "Inert until the Regeling schema (sibling verordeningenregister) lands — REQ-WOO-001. PLACEHOLDER informatiecategorie — copy the exact wetten-en-algemeen-verbindende-voorschriften concept URI verbatim at implementation." - } - ], - "woo-bestuursorgaan": [ - { - "slug": "woo-bestuursorgaan-gemeenteraad-amsterdam", - "governanceBody": "gemeenteraad-amsterdam", - "governingBody": "gm0344", - "label": "Gemeenteraad (example)", - "active": true, - "notes": "EXAMPLE bestuursorgaan TOOI gemeente-identificatie only (gm0344 is the id the records-management-archiving MDTO archiefvormer convention uses as its documented example). Replace with the real bestuursorgaan identifier of this governance body at implementation. The instance-wide default bestuursorgaan lives in app config (admin Woo section, REQ-WOO-006); this object is the per-governance-body override." - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/59-member-onboarding.json b/lib/Settings/register.d/59-member-onboarding.json index 097aef823..09313b785 100644 --- a/lib/Settings/register.d/59-member-onboarding.json +++ b/lib/Settings/register.d/59-member-onboarding.json @@ -1,290 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the member onboarding/offboarding trajecten (member-onboarding). References resolve by slug against existing decidesk seed objects (person: marie-janssen/jan-de-vries/janneke-de-bruin; governance-body: gemeenteraad-amsterdam; meeting: raadsvergadering-2025-01-15). The nil UUID 00000000-0000-0000-0000-000000000000 is an obvious placeholder for a Membership reference where no matching seed Membership object exists at seed time. DECLARATIVE-CORE-ONLY SCOPE (ADR-031/ADR-037): this fragment ships the OnboardingTraject + OffboardingTraject schemas, their canonical lifecycle + step-reminder notification dialects, and demo seeds. The imperative surfaces the design calls out — NC group provisioning/revocation (OnboardingProvisioningService/IGroupManager), Files induction-pack delivery (InductionPackService), and the raadswisseling Member-Import diff (RaadswisselingService) — are OUT of this core and DEFERRED; only the traject + steps + status they operate on are modelled here. One onboarding traject seeds a groepen-toewijzen step with a past dueDate so the overdue-steps KPI and the overdue rappel are non-zero on a fresh install (ADR-016, design Seed Data).", - "objects": { - "onboarding-traject": [ - { - "slug": "onboarding-marie-janssen-raadswisseling", - "person": "marie-janssen", - "targetBody": "gemeenteraad-amsterdam", - "targetRole": "member", - "trigger": "council-turnover-batch", - "batch": "raadswisseling-2026", - "lifecycle": "in-execution", - "ncAccount": "mjanssen", - "membership": "00000000-0000-0000-0000-000000000000", - "swearingInDate": "2026-03-26", - "beëdigingsType": "affirmation", - "swearingInMeeting": "raadsvergadering-2025-01-15", - "steps": [ - { - "stepType": "swearing-in", - "title": "Beëdiging vastleggen", - "status": "completed", - "mandatory": true, - "completedAt": "2026-03-26T20:15:00Z", - "completedBy": "griffier", - "reference": "raadsvergadering-2025-01-15", - "note": "Belofte afgelegd tijdens de installatievergadering." - }, - { - "stepType": "account-linking", - "title": "Nextcloud-account koppelen", - "status": "completed", - "mandatory": true, - "completedAt": "2026-03-27T09:00:00Z", - "completedBy": "griffier", - "reference": "mjanssen" - }, - { - "stepType": "assign-groups", - "title": "Groepen en RBAC-scope toewijzen", - "status": "open", - "mandatory": true, - "dueDate": "2026-06-01", - "note": "Wacht op bevestiging body-role→groep-mapping (drijft de overdue-KPI en het overdue-rappel)." - }, - { - "stepType": "induction-pack", - "title": "Introductiepakket bezorgen", - "status": "open", - "mandatory": false, - "dueDate": "2026-06-15", - "note": "iPad reserveren." - }, - { - "stepType": "ancillary-positions-intake", - "title": "Nevenfuncties uitvragen", - "status": "open", - "mandatory": true, - "dueDate": "2026-06-15" - }, - { - "stepType": "political-group-assignment", - "title": "Fractie toewijzen", - "status": "open", - "mandatory": false, - "dueDate": "2026-06-15" - } - ] - }, - { - "slug": "onboarding-jan-de-vries-opvolging", - "person": "jan-de-vries", - "targetBody": "gemeenteraad-amsterdam", - "targetRole": "member", - "trigger": "interim-succession", - "lifecycle": "started", - "steps": [ - { - "stepType": "swearing-in", - "title": "Beëdiging vastleggen", - "status": "open", - "mandatory": true, - "dueDate": "2026-08-15" - }, - { - "stepType": "account-linking", - "title": "Nextcloud-account koppelen", - "status": "open", - "mandatory": true, - "dueDate": "2026-08-15" - }, - { - "stepType": "assign-groups", - "title": "Groepen en RBAC-scope toewijzen", - "status": "open", - "mandatory": true, - "dueDate": "2026-08-20" - }, - { - "stepType": "induction-pack", - "title": "Introductiepakket bezorgen", - "status": "open", - "mandatory": false, - "dueDate": "2026-08-22" - }, - { - "stepType": "ancillary-positions-intake", - "title": "Nevenfuncties uitvragen", - "status": "open", - "mandatory": true, - "dueDate": "2026-08-22" - }, - { - "stepType": "political-group-assignment", - "title": "Fractie toewijzen", - "status": "open", - "mandatory": false, - "dueDate": "2026-08-22" - } - ] - }, - { - "slug": "onboarding-janneke-de-bruin-nieuw-lid", - "person": "janneke-de-bruin", - "targetBody": "gemeenteraad-amsterdam", - "targetRole": "treasurer", - "trigger": "new-member", - "lifecycle": "completed", - "ncAccount": "jdebruin", - "membership": "00000000-0000-0000-0000-000000000000", - "swearingInDate": "2025-11-10", - "beëdigingsType": "oath", - "swearingInMeeting": "raadsvergadering-2025-01-15", - "steps": [ - { - "stepType": "swearing-in", - "title": "Beëdiging vastleggen", - "status": "completed", - "mandatory": true, - "completedAt": "2025-11-10T20:00:00Z", - "completedBy": "griffier", - "reference": "raadsvergadering-2025-01-15", - "note": "Eed afgelegd bij aanvang bestuurslidmaatschap (ALV-gekozen — vereniging-analoog, demonstreert het niet-gemeentelijke domein)." - }, - { - "stepType": "account-linking", - "title": "Nextcloud-account koppelen", - "status": "completed", - "mandatory": true, - "completedAt": "2025-11-11T09:00:00Z", - "completedBy": "griffier", - "reference": "jdebruin" - }, - { - "stepType": "assign-groups", - "title": "Groepen en RBAC-scope toewijzen", - "status": "completed", - "mandatory": true, - "completedAt": "2025-11-11T09:30:00Z", - "completedBy": "griffier", - "note": "Toegevoegd aan penningmeester-groep; RBAC-scope volgt via de role→scope-projectie." - }, - { - "stepType": "induction-pack", - "title": "Introductiepakket bezorgen", - "status": "completed", - "mandatory": false, - "completedAt": "2025-11-12T10:00:00Z", - "completedBy": "griffier", - "reference": "/Introductiepakket-JdeBruin" - }, - { - "stepType": "ancillary-positions-intake", - "title": "Nevenfuncties uitvragen", - "status": "skipped", - "mandatory": false, - "note": "Geen nevenfuncties opgegeven; stap overgeslagen (verplicht false)." - }, - { - "stepType": "political-group-assignment", - "title": "Fractie toewijzen", - "status": "completed", - "mandatory": false, - "completedAt": "2025-11-12T10:15:00Z", - "completedBy": "griffier" - } - ] - } - ], - "offboarding-traject": [ - { - "slug": "offboarding-jan-de-vries-raadswisseling", - "person": "jan-de-vries", - "body": "gemeenteraad-amsterdam", - "membership": "00000000-0000-0000-0000-000000000000", - "trigger": "council-turnover-batch", - "batch": "raadswisseling-2026", - "endDate": "2026-03-29", - "endReason": "end-of-council-membership", - "lifecycle": "in-execution", - "steps": [ - { - "stepType": "end-membership", - "title": "Lidmaatschap einddateren", - "status": "completed", - "mandatory": true, - "completedAt": "2026-03-29T18:00:00Z", - "completedBy": "griffier", - "note": "endDate = eindeDatum (person-and-membership)." - }, - { - "stepType": "revoke-groups", - "title": "Groepen en RBAC-scope intrekken", - "status": "open", - "mandatory": true, - "dueDate": "2026-03-30", - "note": "Fail-closed en altijd verplicht: traject kan niet naar afgerond zolang deze stap open is (REQ-MOB-008)." - }, - { - "stepType": "personal-data-note", - "title": "Persoonsgegevens-notitie (AVG)", - "status": "open", - "mandatory": true, - "dueDate": "2026-04-05", - "note": "Verwijst naar de eigen-annotaties-export van document-annotations; geen eigen export." - }, - { - "stepType": "exit-confirmation", - "title": "Exit bevestigen", - "status": "open", - "mandatory": true, - "dueDate": "2026-04-05" - } - ] - }, - { - "slug": "offboarding-janneke-de-bruin-individueel", - "person": "janneke-de-bruin", - "body": "gemeenteraad-amsterdam", - "membership": "00000000-0000-0000-0000-000000000000", - "trigger": "individual", - "endDate": "2026-01-15", - "endReason": "resignation", - "lifecycle": "completed", - "exitConfirmedBy": "griffier", - "exitConfirmedOn": "2026-01-20T14:00:00Z", - "steps": [ - { - "stepType": "end-membership", - "title": "Lidmaatschap einddateren", - "status": "completed", - "mandatory": true, - "completedAt": "2026-01-15T17:00:00Z", - "completedBy": "griffier" - }, - { - "stepType": "revoke-groups", - "title": "Groepen en RBAC-scope intrekken", - "status": "completed", - "mandatory": true, - "completedAt": "2026-01-15T17:30:00Z", - "completedBy": "griffier", - "note": "Body-role-gemapte groepen verwijderd; niet-gerelateerde groepen ongemoeid." - }, - { - "stepType": "personal-data-note", - "title": "Persoonsgegevens-notitie (AVG)", - "status": "completed", - "mandatory": true, - "completedAt": "2026-01-18T11:00:00Z", - "completedBy": "griffier" - }, - { - "stepType": "exit-confirmation", - "title": "Exit bevestigen", - "status": "completed", - "mandatory": true, - "completedAt": "2026-01-20T14:00:00Z", - "completedBy": "griffier" - } - ] - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/60-advisory-opinion-workflow.json b/lib/Settings/register.d/60-advisory-opinion-workflow.json index f938fb977..40ac209ba 100644 --- a/lib/Settings/register.d/60-advisory-opinion-workflow.json +++ b/lib/Settings/register.d/60-advisory-opinion-workflow.json @@ -1,82 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the advisory-opinion-workflow capability (adviesaanvraag / advies). Two new schemas: Adviesaanvraag (slug adviesaanvraag) and Advies (slug advies). References resolve by slug against existing decidesk seed objects (governance-body gemeenteraad-amsterdam) or against same-fragment slugs (jongerenraad / adviesraad-sociaal-domein / the aanvraag slugs); the nil UUID 00000000-0000-0000-0000-000000000000 is an obvious placeholder where no matching seed object exists (College body, related Decision, advisory DecisionStage, recorder Person). Two advisory bodies are appended to the governance-body seed array (deepMergeConfig concatenates list arrays, ADR-037) with bodyType advisory-body. DEFERRED DEPENDENCY (design D2, out of this DECLARATIVE-CORE scope): the value 'advisory-body' must be added additively to the GovernanceBody bodyType enum in lib/Settings/decidesk_register.json (a fragment cannot extend an existing schema's enum). Until that base edit lands these two seeded bodies will fail bodyType enum validation on import; the enum edit + the Decision verantwoording fields + the AdviceAccountabilityGuard are the imperative/base-edit tail of this change and are intentionally NOT in this fragment. Aanvraag 1 is non-terminal (in-behandeling) past its requestedByDate so the overdue rappel + open-KPI are non-zero on a fresh install; aanvraag 2 sits in advies-uitgebracht (KPI 'Adviezen wachtend op afdoening' non-zero) and wraps an in-route advisory stage; aanvraag 3 exercises the full flow incl. a deviating besluit, verantwoording recorded on the aanvraag, and live publication (ADR-016 testability).", - "objects": { - "governance-body": [ - { - "slug": "jongerenraad", - "name": "Jongerenraad", - "bodyType": "advisory-body", - "workflowTemplate": "citizen" - }, - { - "slug": "adviesraad-sociaal-domein", - "name": "Adviesraad Sociaal Domein", - "bodyType": "advisory-body", - "workflowTemplate": "legislative" - } - ], - "advice-request": [ - { - "slug": "adviesaanvraag-jongerenhuisvesting", - "subject": "Beleidsnota jongerenhuisvesting 2027–2031", - "question": "Sluit de nota aan bij de woonbehoeften van jongeren van 18–27 jaar?", - "requestingBody": "gemeenteraad-amsterdam", - "advisoryBody": "jongerenraad", - "sentDate": "2026-05-04", - "requestedByDate": "2026-06-15", - "lifecycle": "in-progress" - }, - { - "slug": "adviesaanvraag-inkoopbeleid-wmo", - "subject": "Herziening inkoopbeleid Wmo-ondersteuning", - "question": "Welke gevolgen heeft het voorgenomen inkoopbeleid voor cliënten en mantelzorgers?", - "requestingBody": "00000000-0000-0000-0000-000000000000", - "advisoryBody": "adviesraad-sociaal-domein", - "sentDate": "2026-03-02", - "requestedByDate": "2026-04-13", - "lifecycle": "advice-issued", - "relatedDecision": "00000000-0000-0000-0000-000000000000", - "advisoryStage": "00000000-0000-0000-0000-000000000000" - }, - { - "slug": "adviesaanvraag-skatepark-locatie", - "subject": "Locatiekeuze skatepark centrum", - "question": "Welke van de drie kandidaat-locaties heeft de voorkeur van jongeren?", - "requestingBody": "gemeenteraad-amsterdam", - "advisoryBody": "jongerenraad", - "sentDate": "2026-01-12", - "requestedByDate": "2026-02-16", - "lifecycle": "completed", - "relatedDecision": "00000000-0000-0000-0000-000000000000", - "accountabilityText": "De raad kiest locatie B in afwijking van het advies (locatie A) vanwege geluidsnormen; met de jongerenraad is een evaluatie na één jaar afgesproken.", - "accountabilityDate": "2026-03-24", - "publicationDate": "2026-03-25T09:00:00Z" - } - ], - "advies": [ - { - "slug": "advies-inkoopbeleid-wmo", - "adviceRequest": "adviesaanvraag-inkoopbeleid-wmo", - "tenor": "positive-with-reservations", - "summary": "De adviesraad adviseert positief, mits de continuïteit van lopende ondersteuning wordt geborgd en cliënten actief worden geïnformeerd.", - "adviceDate": "2026-04-10", - "recordedBy": "00000000-0000-0000-0000-000000000000", - "publicationDate": "2026-04-12T09:00:00Z" - }, - { - "slug": "advies-skatepark-locatie", - "adviceRequest": "adviesaanvraag-skatepark-locatie", - "tenor": "negative", - "summary": "De jongerenraad adviseert negatief over locatie B en positief over locatie A vanwege bereikbaarheid.", - "adviceDate": "2026-02-14", - "recordedBy": "00000000-0000-0000-0000-000000000000", - "publicationDate": "2026-03-25T09:00:00Z" - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/61-appointments-and-terms.json b/lib/Settings/register.d/61-appointments-and-terms.json index 881b785d3..8b4b73457 100644 --- a/lib/Settings/register.d/61-appointments-and-terms.json +++ b/lib/Settings/register.d/61-appointments-and-terms.json @@ -1,93 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the appointments & terms register (appointments-and-terms, fragment 61 / ADR-016). References resolve by slug against existing decidesk seed objects (governance-body auditcommissie-provincie-nh / raad-van-commissarissen-acme-bv, person marie-janssen). The nil UUID 00000000-0000-0000-0000-000000000000 is an obvious placeholder where no matching seed object exists at seed time — RoosterRegel Memberships are unresolved because no Membership is seeded for the auditcommissie/ACME-RvC bodies, so the derived persoonNaam carries the name instead. Covers the three remaining schemas across the municipal committee and corporate RvC domains (the Voordracht schema and its 3 seeds were retired and re-authored as Decision decisionType=appointment seeds by the appointment-decision-type-schema change): 2 TermijnRegelingen, 2 RoosterVanAftreden (one published RvC rooster with publicationDate, one unpublished municipal committee rooster), and 5 RoosterRegels including one inside the 6-month rappel window (2026-11-01, drives the KPI + rappel demo) and at its maximum consecutive term (termijnNummer 2, herbenoembaar false, drives the advisory warning).", - "objects": { - "termijn-regeling": [ - { - "slug": "termijn-regeling-auditcommissie", - "body": "auditcommissie-provincie-nh", - "termDurationMonths": 48, - "notes": "Benoeming voor de duur van de raadsperiode; geen maximum aan aansluitende termijnen." - }, - { - "slug": "termijn-regeling-rvc-acme", - "body": "raad-van-commissarissen-acme-bv", - "termDurationMonths": 48, - "maxConsecutivePeriods": 2, - "notes": "Statutair: eenmaal herbenoembaar (art. 12 statuten)." - } - ], - "rooster-van-aftreden": [ - { - "slug": "rooster-rvc-acme", - "body": "raad-van-commissarissen-acme-bv", - "generatedOn": "2026-07-01T09:00:00Z", - "generatedBy": "Griffie", - "publicationDate": "2026-07-02T09:00:00Z" - }, - { - "slug": "rooster-auditcommissie", - "body": "auditcommissie-provincie-nh", - "generatedOn": "2026-07-01T09:00:00Z", - "generatedBy": "Griffie" - } - ], - "rooster-regel": [ - { - "slug": "rooster-regel-rvc-vanduin", - "schedule": "rooster-rvc-acme", - "membership": "00000000-0000-0000-0000-000000000000", - "personName": "J. van Duin", - "role": "member", - "termNumber": 1, - "endTermDate": "2030-09-10", - "reappointable": true - }, - { - "slug": "rooster-regel-rvc-dewit", - "schedule": "rooster-rvc-acme", - "membership": "00000000-0000-0000-0000-000000000000", - "personName": "P. de Wit", - "role": "chair", - "termNumber": 2, - "endTermDate": "2026-11-01", - "reappointable": false, - "rappelStatus": "reminder-6-months" - }, - { - "slug": "rooster-regel-rvc-smit", - "schedule": "rooster-rvc-acme", - "membership": "00000000-0000-0000-0000-000000000000", - "personName": "A. Smit", - "role": "member", - "termNumber": 1, - "endTermDate": "2028-03-15", - "reappointable": true - }, - { - "slug": "rooster-regel-auditcommissie-jansen", - "schedule": "rooster-auditcommissie", - "membership": "00000000-0000-0000-0000-000000000000", - "personName": "S. Jansen", - "role": "member", - "termNumber": 1, - "endTermDate": "2030-09-10", - "reappointable": true - }, - { - "slug": "rooster-regel-auditcommissie-bakker", - "schedule": "rooster-auditcommissie", - "membership": "00000000-0000-0000-0000-000000000000", - "personName": "K. Bakker", - "role": "member", - "termNumber": 1, - "endTermDate": "2027-05-01", - "reappointable": true - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/62-interests-and-integrity.json b/lib/Settings/register.d/62-interests-and-integrity.json index 0450fcf78..ecc563d70 100644 --- a/lib/Settings/register.d/62-interests-and-integrity.json +++ b/lib/Settings/register.d/62-interests-and-integrity.json @@ -1,141 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the interests-and-integrity registers (nevenfuncties, geschenken, integriteitsbeleid). References resolve by slug against existing decidesk seed objects (Person / GovernanceBody); the nil UUID 00000000-0000-0000-0000-000000000000 is an obvious placeholder where no matching seed object exists. Two Integriteitsbeleid policy objects (gemeenteraad: openbaar / EUR 50 / public gifts; RvC Waterschap Amstel: intern / EUR 100 / internal). Five Nevenfunctie objects: one openbaar+published with a STALE reviewedAt (14 months ago) so the dashboard KPI and compliance panel are non-zero on a fresh install (ADR-016); one q.q.; one still gemeld (pending verification); one intern RvC mirroring the Membership.otherPositions seed string 'RvC Stedin (vice-voorzitter)' as a structured object (the supersession story made visible); one beëindigd with endDate. One seeded council member (femke-halsema, voorzitter) deliberately holds NO nevenfunctie so the compliance panel's 'geen opgave geregistreerd' row is demoable. Three Geschenk objects: aanvaard below threshold + published (body policy public), geweigerd boven-drempel + published, overgedragen not-public (RvC policy). References resolve by slug; deepMergeConfig concatenates list arrays (ADR-037).", - "objects": { - "integriteitsbeleid": [ - { - "slug": "beleid-gemeenteraad", - "governanceBody": "gemeenteraad-amsterdam", - "ancillaryPositionDisclosureDefault": "public", - "giftThresholdAmount": 50, - "giftsPublic": true, - "integrityNotificationGroup": "decidesk-burgemeester" - }, - { - "slug": "beleid-rvc-waterschap", - "governanceBody": "rvc-waterschap-amstel", - "ancillaryPositionDisclosureDefault": "internal", - "giftThresholdAmount": 100, - "giftsPublic": false, - "integrityNotificationGroup": "decidesk-compliance" - } - ], - "nevenfunctie": [ - { - "slug": "nf-bestuurslid-welzijn", - "person": "marie-janssen", - "governanceBody": "gemeenteraad-amsterdam", - "organisation": "Stichting Welzijn Noord", - "role": "bestuurslid", - "remunerated": false, - "hoursIndication": "4 uur/week", - "qualitateQua": false, - "startDate": "2024-03-01", - "declaredAt": "2024-03-05", - "reviewedAt": "2025-05-15", - "lifecycle": "public", - "publicationDate": "2024-03-10T09:00:00Z" - }, - { - "slug": "nf-gr-afvalschap-qq", - "person": "jan-de-vries", - "governanceBody": "gemeenteraad-amsterdam", - "organisation": "Gemeenschappelijke Regeling Afvalschap", - "role": "lid algemeen bestuur", - "remunerated": false, - "qualitateQua": true, - "startDate": "2023-05-01", - "declaredAt": "2023-05-08", - "reviewedAt": "2026-06-15", - "lifecycle": "public", - "publicationDate": "2023-05-12T09:00:00Z" - }, - { - "slug": "nf-docent-hogeschool", - "person": "marie-janssen", - "governanceBody": "gemeenteraad-amsterdam", - "organisation": "Hogeschool Amsterdam", - "role": "docent bestuurskunde", - "remunerated": true, - "hoursIndication": "8 uur/week", - "qualitateQua": false, - "startDate": "2025-09-01", - "declaredAt": "2025-09-03", - "lifecycle": "reported" - }, - { - "slug": "nf-rvc-stedin", - "person": "janneke-de-bruin", - "governanceBody": "rvc-waterschap-amstel", - "organisation": "Stedin", - "role": "RvC vice-voorzitter", - "remunerated": true, - "qualitateQua": false, - "startDate": "2022-01-01", - "declaredAt": "2022-01-10", - "reviewedAt": "2026-06-15", - "lifecycle": "internal" - }, - { - "slug": "nf-adviseur-beeindigd", - "person": "jan-de-vries", - "governanceBody": "gemeenteraad-amsterdam", - "organisation": "Adviesbureau De Kern", - "role": "adviseur", - "remunerated": true, - "qualitateQua": false, - "startDate": "2021-06-01", - "endDate": "2025-12-31", - "declaredAt": "2021-06-05", - "lifecycle": "ended", - "publicationDate": "2021-06-10T09:00:00Z" - } - ], - "geschenk": [ - { - "slug": "gs-boek-delegatie", - "recipient": "marie-janssen", - "governanceBody": "gemeenteraad-amsterdam", - "type": "gift", - "giver": "Delegatie gemeente Aken", - "description": "Fotoboek stedenband", - "estimatedValue": 20, - "receivedOn": "2026-01-20", - "decision": "accepted", - "declaredAt": "2026-01-21", - "publicationDate": "2026-01-25T09:00:00Z" - }, - { - "slug": "gs-diner-projectontwikkelaar", - "recipient": "marie-janssen", - "governanceBody": "gemeenteraad-amsterdam", - "type": "invitation", - "giver": "Projectontwikkelaar BV", - "description": "Diner nieuwjaarsreceptie", - "estimatedValue": 95, - "receivedOn": "2026-01-08", - "decision": "refused", - "notes": "Boven het drempelbedrag; uitnodiging geweigerd conform gedragscode.", - "declaredAt": "2026-01-09", - "publicationDate": "2026-01-15T09:00:00Z" - }, - { - "slug": "gs-congres-uitnodiging", - "recipient": "janneke-de-bruin", - "governanceBody": "rvc-waterschap-amstel", - "type": "invitation", - "giver": "Brancheorganisatie Water", - "description": "Congres met overnachting", - "estimatedValue": 400, - "receivedOn": "2026-02-03", - "decision": "transferred", - "notes": "Deelname overgedragen aan de organisatie; geen persoonlijk voordeel.", - "declaredAt": "2026-02-04" - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/63-member-proxy-authorization.json b/lib/Settings/register.d/63-member-proxy-authorization.json index 8c829469c..04a26e92f 100644 --- a/lib/Settings/register.d/63-member-proxy-authorization.json +++ b/lib/Settings/register.d/63-member-proxy-authorization.json @@ -1,83 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the member-proxy-authorization capability (fragment 63, ADR-037). The new proxy-authorization schema carries the signed machtiging instrument that sits beside a proxy row on the existing vote schema; the process-template seed adds one DUPLICATED (builtIn:false) template demonstrating the per-body override path. References resolve by slug against existing decidesk seed objects (participant, meeting, and the seed proxy row stem-proxy-vandam-begroting on the vote schema); the nil UUID 00000000-0000-0000-0000-000000000000 is an obvious placeholder where no matching seed object exists (grantors Van Dam and Jansen have no Participant seed). Object 1 (machtiging-vandam-begroting) completes the existing seed proxy vote with a fully getekend + countersigned instrument so the happy path is demonstrable on a fresh install; object 2 (machtiging-alv-jansen-ongetekend) stays ongetekend so the sign action and the requireSignedProxy refusal are demoable; object 3 (machtiging-devries-ingetrokken) demonstrates the signed revocation act (revokedAt + revocationSignatureStatus getekend). The duplicated template ALV met statutaire volmachtgrens (cloned from association-alv, builtIn:false) carries votingRule.maxProxiesPerHolder 1 and requireSignedProxy true so the per-body override is demonstrable without editing read-only built-ins; the built-in templates ship both keys UNSET (global fallback, behaviour-identical upgrade). NOTE (app-wide limitation, consistent with sibling fragments 45/54/55): relation refs stored as slugs may not resolve on detail pages until the register import maps them to UUIDs.", - "objects": { - "proxy-authorization": [ - { - "slug": "machtiging-vandam-begroting", - "grantor": "00000000-0000-0000-0000-000000000000", - "holder": "jan-de-vries", - "meeting": "raadsvergadering-2025-01-15", - "proxyVote": "stem-proxy-vandam-begroting", - "document": "00000000-0000-0000-0000-000000000000", - "signatureStatus": "signed", - "signedAt": "2026-06-02T09:15:00Z", - "signingReference": "docudesk:sign:seed-vandam-begroting", - "countersignStatus": "signed", - "countersignedAt": "2026-06-02T11:40:00Z" - }, - { - "slug": "machtiging-alv-jansen-ongetekend", - "grantor": "00000000-0000-0000-0000-000000000000", - "holder": "marie-janssen", - "meeting": "ledenvergadering-vng-voorjaar-2025", - "signatureStatus": "unsigned" - }, - { - "slug": "machtiging-devries-ingetrokken", - "grantor": "jan-de-vries", - "holder": "pieter-bakker", - "meeting": "raadsvergadering-2025-01-15", - "document": "00000000-0000-0000-0000-000000000000", - "signatureStatus": "signed", - "signedAt": "2026-05-01T10:00:00Z", - "revokedAt": "2026-05-20T14:30:00Z", - "revocationSignatureStatus": "signed", - "revocationSigningReference": "docudesk:sign:seed-devries-revocatie" - } - ], - "process-template": [ - { - "slug": "association-alv-statutaire-volmacht", - "name": "ALV met statutaire volmachtgrens", - "description": "Duplicated Association ALV template (builtIn:false) demonstrating the per-body override: statuten cap one proxy per holder and require a signed machtiging. Cloned from the association-alv built-in; the built-in itself ships both new keys unset (global fallback).", - "context": "association", - "builtIn": false, - "initialState": "draft", - "stateMachine": { - "states": [ - { "name": "draft" }, - { "name": "proposed" }, - { "name": "deliberating" }, - { "name": "voting" }, - { "name": "decided" }, - { "name": "enacted" }, - { "name": "archived" } - ], - "transitions": [ - { "name": "propose", "from": "draft", "to": "proposed" }, - { "name": "deliberate", "from": "proposed", "to": "deliberating" }, - { "name": "openVoting", "from": "deliberating", "to": "voting", "chairOnly": true, "guards": [ "quorum_met" ] }, - { "name": "decide", "from": "voting", "to": "decided" }, - { "name": "enact", "from": "decided", "to": "enacted" }, - { "name": "archive", "from": "enacted", "to": "archived" } - ] - }, - "votingRule": { - "voteThreshold": "simple-majority", - "abstentionHandling": "exclude", - "tieBreakRule": "rejected", - "maxProxiesPerHolder": 1, - "requireSignedProxy": true - }, - "quorumRequired": true, - "quorumRule": "50%+1 of members present or represented", - "allowDecideWithoutVote": false - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/65-embargo-geheimhouding.json b/lib/Settings/register.d/65-embargo-geheimhouding.json index 2c6caf042..f55f9f073 100644 --- a/lib/Settings/register.d/65-embargo-geheimhouding.json +++ b/lib/Settings/register.d/65-embargo-geheimhouding.json @@ -1,137 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the embargo-geheimhouding capability (DECLARATIVE CORE only). Two new schemas: GeheimhoudingGrond (slug geheimhouding-grond, a Schema.org DefinedTerm managed ground list) and Geheimhouding (slug geheimhouding, a Schema.org Action juridical record). References resolve by slug: geheimhouding.ground -> a same-fragment geheimhouding-grond slug; geheimhouding.imposedByBody -> the existing decidesk seed governance-body gemeenteraad-amsterdam. The nil UUID 00000000-0000-0000-0000-000000000000 is an obvious placeholder for the target document/agenda-item/decision and for the opheffingsbesluit, where no matching seed object exists on a clean install. IMPERATIVE / OUT-OF-CORE (design): the impose/bekrachtig/opheffing workflows (GeheimhoudingService), the timed EmbargoReleaseJob (OCP TimedJob flipping DigitalDocument.embargoActive), the publication-guard extension, the view-audit logging, the 4 workflow routes, and the additive embargoUntil/embargoActive/embargoAudience properties on the EXISTING DigitalDocument schema (a fragment cannot extend an existing schema; that edit lands in lib/Settings/decidesk_register.json) are ALL intentionally NOT in this declarative fragment. This fragment ships only the two schemas, their canonical lifecycle/notifications/aggregations dialects, and the seed grounds + geheimhouding records. Ground seeds carry BOTH the post-2023 Gemeentewet labels (art. 87-89, Wet bevorderen integriteit en functioneren decentraal bestuur) AND the pre-2023 labels (voorheen art. 25/55/86) in legacyCitation, plus the Woo art. 5.1 lid 1 (absolute) and lid 2 (relatieve) gronden; whether bekrachtiging is required is a per-ground property (requiresBekrachtiging), NEVER hardcoded. The three geheimhouding seeds are testable on a fresh install: seed 1 (opgelegd, bekrachtigingDeadline in the FUTURE) feeds the awaiting-bekrachtiging KPI; seed 2 (opgelegd, bekrachtigingDeadline in the PAST, no besluit) feeds the OVERDUE KPI fail-visible; seed 3 (opgeheven with opheffingsbesluit + conditions) feeds the awaiting-publication KPI.", - "objects": { - "geheimhouding-grond": [ - { - "slug": "grond-raadsstukken", - "name": "Geheimhouding raadsstukken", - "citation": "Gemeentewet art. 87-89", - "legacyCitation": "voorheen art. 25", - "category": "municipalities-act", - "requiresRatification": true, - "description": "Geheimhouding opgelegd op stukken bestemd voor of behandeld door de raad. Onder het regime van de Wet bevorderen integriteit en functioneren decentraal bestuur (2023) geldt Gemeentewet art. 87-89; voorheen art. 25.", - "builtIn": true, - "active": true - }, - { - "slug": "grond-collegestukken", - "name": "Geheimhouding collegestukken", - "citation": "Gemeentewet art. 87-89", - "legacyCitation": "voorheen art. 55", - "category": "municipalities-act", - "requiresRatification": false, - "description": "Geheimhouding opgelegd door of namens het college op collegestukken. Post-2023 Gemeentewet art. 87-89; voorheen art. 55.", - "builtIn": true, - "active": true - }, - { - "slug": "grond-commissiestukken", - "name": "Geheimhouding commissiestukken", - "citation": "Gemeentewet art. 87-89", - "legacyCitation": "voorheen art. 86", - "category": "municipalities-act", - "requiresRatification": true, - "description": "Geheimhouding opgelegd in een raadscommissie op commissiestukken; bekrachtiging door de raad vereist. Post-2023 Gemeentewet art. 87-89; voorheen art. 86.", - "builtIn": true, - "active": true - }, - { - "slug": "grond-woo-kroon-veiligheid", - "name": "Eenheid van de Kroon / veiligheid van de Staat", - "citation": "Woo art. 5.1 lid 1", - "legacyCitation": null, - "category": "woo-absolute", - "requiresRatification": false, - "description": "Absolute uitzonderingsgrond (Woo art. 5.1 lid 1): eenheid van de Kroon en veiligheid van de Staat.", - "builtIn": true, - "active": true - }, - { - "slug": "grond-woo-bedrijfsgegevens", - "name": "Vertrouwelijk verstrekte bedrijfs- en fabricagegegevens", - "citation": "Woo art. 5.1 lid 1", - "legacyCitation": null, - "category": "woo-absolute", - "requiresRatification": false, - "description": "Absolute uitzonderingsgrond (Woo art. 5.1 lid 1): vertrouwelijk aan de overheid meegedeelde bedrijfs- en fabricagegegevens.", - "builtIn": true, - "active": true - }, - { - "slug": "grond-woo-persoonlijke-levenssfeer", - "name": "Eerbiediging van de persoonlijke levenssfeer", - "citation": "Woo art. 5.1 lid 2", - "legacyCitation": null, - "category": "woo-relative", - "requiresRatification": false, - "description": "Relatieve uitzonderingsgrond (Woo art. 5.1 lid 2): eerbiediging van de persoonlijke levenssfeer.", - "builtIn": true, - "active": true - }, - { - "slug": "grond-woo-financieel-economisch", - "name": "Financiële en economische belangen van het bestuursorgaan", - "citation": "Woo art. 5.1 lid 2", - "legacyCitation": null, - "category": "woo-relative", - "requiresRatification": false, - "description": "Relatieve uitzonderingsgrond (Woo art. 5.1 lid 2): financiële en economische belangen van het bestuursorgaan.", - "builtIn": true, - "active": true - }, - { - "slug": "grond-statutair", - "name": "Statutaire vertrouwelijkheid (niet-overheid)", - "citation": "statuten/reglement", - "legacyCitation": null, - "category": "other", - "requiresRatification": true, - "description": "Vertrouwelijkheidsgrond voor niet-overheidsgremia (vereniging, RvC, coöperatie) op basis van statuten of huishoudelijk reglement. Illustreert dat het bekrachtigingsvereiste een eigenschap van de configureerbare grond is, niet van de wet.", - "builtIn": true, - "active": true - } - ], - "geheimhouding": [ - { - "slug": "geheimhouding-raadsnota-grondexploitatie", - "scope": "document", - "targetDocument": "00000000-0000-0000-0000-000000000000", - "ground": "grond-raadsstukken", - "imposedBy": "executive-board", - "imposedByBody": "gemeenteraad-amsterdam", - "imposedAt": "2026-06-08T10:00:00Z", - "lifecycle": "imposed", - "ratificationDeadline": "2026-09-30" - }, - { - "slug": "geheimhouding-commissiestuk-vastgoed", - "scope": "item", - "targetAgendaItem": "00000000-0000-0000-0000-000000000000", - "ground": "grond-commissiestukken", - "imposedBy": "chair", - "imposedByBody": "gemeenteraad-amsterdam", - "imposedAt": "2026-03-02T13:30:00Z", - "lifecycle": "imposed", - "ratificationDeadline": "2026-04-01" - }, - { - "slug": "geheimhouding-besluit-personeel", - "scope": "decision", - "targetDecision": "00000000-0000-0000-0000-000000000000", - "ground": "grond-woo-persoonlijke-levenssfeer", - "imposedBy": "body", - "imposedByBody": "gemeenteraad-amsterdam", - "imposedAt": "2026-01-19T09:00:00Z", - "lifecycle": "dissolved", - "dissolutionDecision": "00000000-0000-0000-0000-000000000000", - "liftingDate": "2026-06-25", - "liftingConditions": "openbaar na afronding onderhandelingen" - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/66-organisation-goals.json b/lib/Settings/register.d/66-organisation-goals.json index 38e12d91e..5e909ed60 100644 --- a/lib/Settings/register.d/66-organisation-goals.json +++ b/lib/Settings/register.d/66-organisation-goals.json @@ -1,77 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the organisation-goals register (change: organisation-goals). Five Goal objects spanning all three horizon values, three status values, one parent/child pair (goal-acme-groeidoelstelling-2028 -> goal-acme-mt-operationele-effectiviteit-2026, and goal-amsterdam-klimaatneutraal-2050 -> goal-amsterdam-parkeerbeleid-kwartaal), one owned goal and one body-only (collectively owned) goal. References resolve by slug against existing decidesk seed objects (governanceBody raad-van-bestuur-acme-bv/managementteam-acme-bv/gemeenteraad-amsterdam/ledenraad-vng, Person femke-halsema); the nil UUID 00000000-0000-0000-0000-000000000000 is the established placeholder (ADR-001 precedent, used identically in the termijnagenda/toezeggingen fragments) where no matching seed Person exists for a body with no seeded membership. Cross-links onto EXISTING seed objects (toezegging-schouw-marktplein gets goal: goal-amsterdam-klimaatneutraal-2050; lta-herziening-parkeerbeleid gets goal: goal-amsterdam-parkeerbeleid-kwartaal) are patched directly onto those objects in 45-toezeggingen-ingekomen-stukken.json / 50-termijnagenda.json (see design.md Seed Data), not duplicated here. Objects grouped by schema slug 'goal' (the OR seedData import path resolves the schema from the object key).", - "objects": { - "goal": [ - { - "slug": "goal-acme-groeidoelstelling-2028", - "title": "Duurzame omzetgroei 2028", - "description": "Structurele omzetgroei realiseren binnen de duurzaamheidsdoelstellingen van de raad van bestuur.", - "horizon": "multi-year", - "body": "raad-van-bestuur-acme-bv", - "owner": "00000000-0000-0000-0000-000000000000", - "startDate": "2026-01-01", - "deadline": "2028-12-31", - "status": "active", - "targetValue": 20, - "currentValue": 6, - "unit": "% omzetgroei" - }, - { - "slug": "goal-acme-mt-operationele-effectiviteit-2026", - "title": "Operationele effectiviteit 2026", - "description": "Procesdoorlooptijden binnen norm brengen als uitvoering van de groeidoelstelling.", - "horizon": "annual", - "body": "managementteam-acme-bv", - "owner": "00000000-0000-0000-0000-000000000000", - "startDate": "2026-01-01", - "deadline": "2026-12-31", - "status": "active", - "targetValue": 90, - "currentValue": 78, - "unit": "% doorlooptijd binnen norm", - "parentGoal": "goal-acme-groeidoelstelling-2028" - }, - { - "slug": "goal-amsterdam-klimaatneutraal-2050", - "title": "Amsterdam klimaatneutraal", - "description": "Netto CO2-uitstoot van de gemeentelijke organisatie naar nul in 2050, conform het raadsbesluit klimaatakkoord.", - "horizon": "multi-year", - "body": "gemeenteraad-amsterdam", - "owner": "femke-halsema", - "startDate": "2026-01-01", - "deadline": "2050-01-01", - "status": "active", - "targetValue": 100, - "currentValue": 42, - "unit": "% CO2-reductie behaald" - }, - { - "slug": "goal-amsterdam-parkeerbeleid-kwartaal", - "title": "Herzien parkeerbeleid vastgesteld", - "description": "Vaststellen van het herziene parkeerbeleid binnenstad (koppeling met de termijnagenda).", - "horizon": "quarterly", - "body": "gemeenteraad-amsterdam", - "owner": "00000000-0000-0000-0000-000000000000", - "startDate": "2026-04-01", - "deadline": "2026-09-30", - "status": "at-risk", - "parentGoal": "goal-amsterdam-klimaatneutraal-2050" - }, - { - "slug": "goal-vng-digitale-dienstverlening-2026", - "title": "Digitale dienstverlening leden", - "description": "Alle VNG-leden kunnen digitaal diensten afnemen bij de vereniging.", - "horizon": "annual", - "body": "ledenraad-vng", - "startDate": "2026-01-01", - "deadline": "2026-12-31", - "status": "draft" - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/67-model-debt-cleanup.json b/lib/Settings/register.d/67-model-debt-cleanup.json index 1a66e1fd9..8c11f6e90 100644 --- a/lib/Settings/register.d/67-model-debt-cleanup.json +++ b/lib/Settings/register.d/67-model-debt-cleanup.json @@ -1,57 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Seed objects for the model-debt-cleanup-schema sweep (fragment 67, ADR-037). Demonstrates every new/retargeted property on a FRESHLY-CREATED object, never a patch to an existing seeded row (OpenRegister seed import is create-only). References resolve by slug against existing decidesk base seed objects. besluit-verordening-parkeren-2026 (decision) carries meeting: raadsvergadering-2025-01-15 and agendaItem: begroting-2026-bespreking (REQ-SDM-022, both existing base seed slugs) so the new join is demonstrable on a fresh install. coi-wethouder-vastgoedbelang (conflict-of-interest) references boardMember as the membership seed m-marie-amsterdam (REQ-SDM-023) rather than a participant slug. machtiging-jansen-alv-2026 (proxy-authorization — note the NEW kebab-case seed-object collection key, since this fragment ships together with the slug rename in 63-member-proxy-authorization.json) is a new sibling to the existing machtiging-vandam-begroting/machtiging-alv-jansen-ongetekend/machtiging-devries-ingetrokken fixtures, using person seed slugs marie-janssen/jan-de-vries for grantor/holder and proxyStatus active (REQ-SDM-024); the pre-existing seed objects in 63-member-proxy-authorization.json keep their historical Participant-shaped grantor/holder values untouched — they are the code chain's migration input, not something this schema-only change rewrites. huishoudelijk-reglement-acme-bv (governing-document) carries currentEffectiveDate 2025-09-01 (REQ-SDM-025) on the existing raad-van-bestuur-acme-bv corporate-domain governance body. No seed object demonstrates Person.nextcloudUserId (Task 1b) — that property is populated by the code chain's Participant-to-Person crosswalk repair step, not a fresh seed row here. NOTE (app-wide limitation, consistent with sibling fragments 45/54/55/60/63): relation refs stored as slugs may not resolve on detail pages until the register import maps them to UUIDs.", - "objects": { - "decision": [ - { - "slug": "besluit-verordening-parkeren-2026", - "decisionType": "resolution", - "title": "Verordening parkeren 2026", - "text": "Vaststelling van de verordening parkeren 2026, voortvloeiend uit de bespreking van de kadernota begroting 2026.", - "decisionDate": "2026-06-15", - "outcome": "adopted", - "meeting": "raadsvergadering-2025-01-15", - "agendaItem": "begroting-2026-bespreking" - } - ], - "conflict-of-interest": [ - { - "slug": "coi-wethouder-vastgoedbelang", - "boardMember": "m-marie-amsterdam", - "declarationType": "financial-interest", - "description": "Lid meldt een financieel belang in een vastgoedontwikkeling die onderwerp is van het agendapunt en onthoudt zich van beraadslaging en stemming.", - "severity": "material", - "actionTaken": "recused-from-vote", - "declarationTimestamp": "2026-06-15T19:05:00Z" - } - ], - "proxy-authorization": [ - { - "slug": "machtiging-jansen-alv-2026", - "grantor": "marie-janssen", - "holder": "jan-de-vries", - "meeting": "ledenvergadering-vng-voorjaar-2025", - "signatureStatus": "signed", - "signedAt": "2026-04-10T08:30:00Z", - "signingReference": "docudesk:sign:seed-jansen-alv-2026", - "proxyStatus": "active" - } - ], - "governing-document": [ - { - "slug": "huishoudelijk-reglement-acme-bv", - "type": "internal-regulations", - "citationTitle": "Huishoudelijk reglement ACME B.V.", - "description": "Huishoudelijk reglement van de raad van bestuur, aanvullend op de statuten.", - "governingBody": "raad-van-bestuur-acme-bv", - "isPublic": false, - "status": "in-force", - "currentEffectiveDate": "2025-09-01" - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/68-unified-decision-templates.json b/lib/Settings/register.d/68-unified-decision-templates.json index c1109f62f..027202d8e 100644 --- a/lib/Settings/register.d/68-unified-decision-templates.json +++ b/lib/Settings/register.d/68-unified-decision-templates.json @@ -1,374 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Unified DecisionTemplate schema-declaration fragment (ADR-037 additive pattern; OpenSpec change unified-decision-templates, chain link 1 of 3 per ADR-032). Declares the DecisionTemplate schema and 13 built-in seeds: 5 ported 1:1 from ProcessTemplate (43-process-config-v1.json), 2 ported 1:1 from the urgency-enabled custom templates (46-urgency-policy.json), and 6 ported from VveDecisionTemplate (57-vve-alv-pack.json, context=association, decisionType=resolution, the 2017 modelreglement's categoryRules folded into votingRule/quorumRule). All 13 ship checklist:[] (no built-in acquires a checklist in this change — checklist authoring is consumer-rewrite/admin-UI work). Also supersedes ProcessTemplate/VveDecisionTemplate/ModelreglementPreset non-destructively (x-openregister.active:false, definitions and existing rows kept, mirroring the BoardProxy precedent in 67-model-debt-cleanup.json) and additively retargets VveConfiguration towards a modelReglementVersion enum + majorityOverrides[].templateCategory (schema-level only — OR seed import is create-only, so the existing vve-zeewaarts-configuratie seed object from 57-vve-alv-pack.json is left untouched; a NEW demo object, vve-parkstaete-configuratie, demonstrates the new shape on a fresh install, mirroring the 'demonstrate on a freshly-created object' convention already used in 67-model-debt-cleanup.json). A repair migration (lib/Migration/MigrateLegacyTemplatesToDecisionTemplate.php) back-fills decision-template objects for every live process-template/vve-decision-template object, since seed import never touches objects a prior install already created. No consumer PHP/Vue is rewired in this change (unified-decision-templates-consumer-rewrite scope) — ProcessTemplateService and friends keep reading process-template exactly as before.", - "objects": { - "decision-template": [ - { - "slug": "association-alv", - "name": "Association ALV", - "description": "Standard decision process for a Dutch association general meeting (ALV), BW Book 2.", - "context": "association", - "builtIn": true, - "initialState": "draft", - "stateMachine": { - "states": [ - { "name": "draft" }, - { "name": "proposed" }, - { "name": "deliberating" }, - { "name": "voting" }, - { "name": "decided" }, - { "name": "enacted" }, - { "name": "archived" } - ], - "transitions": [ - { "name": "propose", "from": "draft", "to": "proposed" }, - { "name": "deliberate", "from": "proposed", "to": "deliberating" }, - { "name": "openVoting", "from": "deliberating", "to": "voting", "chairOnly": true, "guards": ["quorum_met"] }, - { "name": "decide", "from": "voting", "to": "decided" }, - { "name": "enact", "from": "decided", "to": "enacted" }, - { "name": "archive", "from": "enacted", "to": "archived" } - ] - }, - "votingRule": { - "voteThreshold": "simple-majority", - "abstentionHandling": "exclude", - "tieBreakRule": "rejected" - }, - "quorumRequired": true, - "quorumRule": "50%+1 of members present or represented", - "allowDecideWithoutVote": false, - "checklist": [] - }, - { - "slug": "association-board", - "name": "Association Board", - "description": "Decision process for an association board (bestuur).", - "context": "association", - "builtIn": true, - "initialState": "draft", - "stateMachine": { - "states": [ - { "name": "draft" }, - { "name": "proposed" }, - { "name": "deliberating" }, - { "name": "voting" }, - { "name": "decided" }, - { "name": "enacted" }, - { "name": "archived" } - ], - "transitions": [ - { "name": "propose", "from": "draft", "to": "proposed" }, - { "name": "deliberate", "from": "proposed", "to": "deliberating" }, - { "name": "openVoting", "from": "deliberating", "to": "voting", "chairOnly": true, "guards": ["quorum_met"] }, - { "name": "decide", "from": "voting", "to": "decided" }, - { "name": "enact", "from": "decided", "to": "enacted" }, - { "name": "archive", "from": "enacted", "to": "archived" } - ] - }, - "votingRule": { - "voteThreshold": "simple-majority", - "abstentionHandling": "exclude", - "tieBreakRule": "chair-decides" - }, - "quorumRequired": true, - "quorumRule": "Majority of board members present", - "allowDecideWithoutVote": false, - "checklist": [] - }, - { - "slug": "corporate-board", - "name": "Corporate Board (BV)", - "description": "Decision process for the management board of a Dutch private limited company (BV).", - "context": "corporate", - "builtIn": true, - "initialState": "draft", - "stateMachine": { - "states": [ - { "name": "draft" }, - { "name": "proposed" }, - { "name": "deliberating" }, - { "name": "voting" }, - { "name": "decided" }, - { "name": "enacted" }, - { "name": "archived" } - ], - "transitions": [ - { "name": "propose", "from": "draft", "to": "proposed" }, - { "name": "deliberate", "from": "proposed", "to": "deliberating" }, - { "name": "openVoting", "from": "deliberating", "to": "voting", "chairOnly": true, "guards": ["quorum_met"] }, - { "name": "decide", "from": "voting", "to": "decided" }, - { "name": "enact", "from": "decided", "to": "enacted" }, - { "name": "archive", "from": "enacted", "to": "archived" } - ] - }, - "votingRule": { - "voteThreshold": "simple-majority", - "abstentionHandling": "exclude", - "tieBreakRule": "chair-decides" - }, - "quorumRequired": true, - "quorumRule": "Quorum per the articles of association", - "allowDecideWithoutVote": false, - "checklist": [] - }, - { - "slug": "municipal-council", - "name": "Municipal Council", - "description": "Legislative decision process for a municipal council (gemeenteraad), Gemeentewet.", - "context": "legislative", - "builtIn": true, - "initialState": "draft", - "stateMachine": { - "states": [ - { "name": "draft" }, - { "name": "proposed" }, - { "name": "deliberating" }, - { "name": "voting" }, - { "name": "decided" }, - { "name": "enacted" }, - { "name": "archived" } - ], - "transitions": [ - { "name": "propose", "from": "draft", "to": "proposed" }, - { "name": "deliberate", "from": "proposed", "to": "deliberating" }, - { "name": "openVoting", "from": "deliberating", "to": "voting", "chairOnly": true, "guards": ["quorum_met", "all_amendments_resolved"] }, - { "name": "decide", "from": "voting", "to": "decided", "chairOnly": true }, - { "name": "enact", "from": "decided", "to": "enacted" }, - { "name": "archive", "from": "enacted", "to": "archived" } - ] - }, - "votingRule": { - "voteThreshold": "simple-majority", - "abstentionHandling": "exclude", - "tieBreakRule": "rejected" - }, - "quorumRequired": true, - "quorumRule": "More than half of the seats occupied (Gemeentewet art. 20)", - "allowDecideWithoutVote": false, - "checklist": [] - }, - { - "slug": "operational-team", - "name": "Operational Team", - "description": "Lightweight decision process for an operational/management team; formal voting rounds are optional.", - "context": "operations", - "builtIn": true, - "initialState": "draft", - "stateMachine": { - "states": [ - { "name": "draft" }, - { "name": "proposed" }, - { "name": "deliberating" }, - { "name": "decided" }, - { "name": "enacted" }, - { "name": "archived" } - ], - "transitions": [ - { "name": "propose", "from": "draft", "to": "proposed" }, - { "name": "deliberate", "from": "proposed", "to": "deliberating" }, - { "name": "decide", "from": "deliberating", "to": "decided" }, - { "name": "enact", "from": "decided", "to": "enacted" }, - { "name": "archive", "from": "enacted", "to": "archived" } - ] - }, - "votingRule": { - "voteThreshold": "simple-majority", - "abstentionHandling": "exclude", - "tieBreakRule": "rejected" - }, - "quorumRequired": false, - "quorumRule": "No formal quorum", - "allowDecideWithoutVote": true, - "checklist": [] - }, - { - "slug": "municipal-council-urgent", - "name": "Municipal Council (urgency-enabled)", - "description": "Municipal council (gemeenteraad) process template with the urgent-decision procedure enabled: college spoedbesluit routed to a mandatory ratification stage at the next regular raadsvergadering.", - "context": "legislative", - "builtIn": false, - "initialState": "draft", - "stateMachine": { - "states": [ - { "name": "draft" }, - { "name": "proposed" }, - { "name": "deliberating" }, - { "name": "voting" }, - { "name": "decided" }, - { "name": "enacted" }, - { "name": "archived" } - ], - "transitions": [ - { "name": "propose", "from": "draft", "to": "proposed" }, - { "name": "deliberate", "from": "proposed", "to": "deliberating" }, - { "name": "openVoting", "from": "deliberating", "to": "voting", "chairOnly": true, "guards": ["quorum_met", "all_amendments_resolved"] }, - { "name": "decide", "from": "voting", "to": "decided", "chairOnly": true }, - { "name": "enact", "from": "decided", "to": "enacted" }, - { "name": "archive", "from": "enacted", "to": "archived" } - ] - }, - "votingRule": { - "voteThreshold": "simple-majority", - "abstentionHandling": "exclude", - "tieBreakRule": "rejected" - }, - "quorumRequired": true, - "quorumRule": "More than half of the seats occupied (Gemeentewet art. 20)", - "allowDecideWithoutVote": false, - "urgencyPolicy": { - "allowedTriggerRoles": ["chair"], - "minimumNoticeFloorHours": 24, - "responseDeadlineHours": { "min": 12, "max": 96 }, - "ratificationRequired": true, - "ratifyingBody": "gemeenteraad-amsterdam" - }, - "checklist": [] - }, - { - "slug": "corporate-board-urgent", - "name": "Corporate Board (urgency-enabled)", - "description": "Corporate management board (RvB) process template with the urgent-decision procedure enabled: urgent resolution decided via an expedited 24h written round, ratified by the Raad van Commissarissen.", - "context": "corporate", - "builtIn": false, - "initialState": "draft", - "stateMachine": { - "states": [ - { "name": "draft" }, - { "name": "proposed" }, - { "name": "deliberating" }, - { "name": "voting" }, - { "name": "decided" }, - { "name": "enacted" }, - { "name": "archived" } - ], - "transitions": [ - { "name": "propose", "from": "draft", "to": "proposed" }, - { "name": "deliberate", "from": "proposed", "to": "deliberating" }, - { "name": "openVoting", "from": "deliberating", "to": "voting", "chairOnly": true, "guards": ["quorum_met"] }, - { "name": "decide", "from": "voting", "to": "decided" }, - { "name": "enact", "from": "decided", "to": "enacted" }, - { "name": "archive", "from": "enacted", "to": "archived" } - ] - }, - "votingRule": { - "voteThreshold": "simple-majority", - "abstentionHandling": "exclude", - "tieBreakRule": "chair-decides" - }, - "quorumRequired": true, - "quorumRule": "Quorum per the articles of association", - "allowDecideWithoutVote": false, - "urgencyPolicy": { - "allowedTriggerRoles": ["chair", "secretary"], - "minimumNoticeFloorHours": 12, - "responseDeadlineHours": { "min": 4, "max": 72 }, - "ratificationRequired": true, - "ratifyingBody": "raad-van-commissarissen-acme-bv" - }, - "checklist": [] - }, - { - "slug": "decharge-bestuur", - "name": "Decharge bestuur", - "description": "Decharge van het bestuur over het afgelopen boekjaar door de algemene ledenvergadering.", - "context": "association", - "decisionType": "resolution", - "templateCategory": "discharge", - "builtIn": true, - "proposedText": "De vergadering verleent het bestuur decharge voor het gevoerde beleid en beheer over het boekjaar {boekjaar}, gehoord de verklaring van de kascommissie.", - "regulationSource": "BW 2:48/2:49", - "votingRule": { "voteThreshold": "simple-majority" }, - "checklist": [] - }, - { - "slug": "vaststelling-jaarrekening", - "name": "Vaststelling jaarrekening", - "description": "Vaststelling van de jaarrekening (exploitatie- en balansoverzicht) van het afgelopen boekjaar.", - "context": "association", - "decisionType": "resolution", - "templateCategory": "annual-accounts", - "builtIn": true, - "proposedText": "De vergadering stelt de jaarrekening over het boekjaar {boekjaar} vast conform het door het bestuur aangeboden exploitatie- en balansoverzicht.", - "regulationSource": "MR 2017 art. 14/15", - "votingRule": { "voteThreshold": "simple-majority" }, - "checklist": [] - }, - { - "slug": "dotatie-reservefonds", - "name": "Dotatie reservefonds", - "description": "Besluit tot dotatie aan het reservefonds voor groot onderhoud.", - "context": "association", - "decisionType": "resolution", - "templateCategory": "reserve-fund-contribution", - "builtIn": true, - "proposedText": "De vergadering besluit over het boekjaar {boekjaar} een bedrag te doteren aan het reservefonds ten behoeve van toekomstig groot onderhoud, conform de MJOP-grondslag.", - "regulationSource": "Woningwet reservefonds (BW 5:126)", - "votingRule": { "voteThreshold": "simple-majority" }, - "checklist": [] - }, - { - "slug": "vaststelling-mjop", - "name": "Vaststelling/actualisatie MJOP", - "description": "Vaststelling of actualisatie van het meerjarenonderhoudsplan (MJOP).", - "context": "association", - "decisionType": "resolution", - "templateCategory": "mjop-adoption", - "builtIn": true, - "proposedText": "De vergadering stelt het meerjarenonderhoudsplan (MJOP) {periode} vast, respectievelijk actualiseert het geldende MJOP conform het aangeboden concept.", - "regulationSource": "MR 2017 art. 14 (MJOP-grondslag)", - "votingRule": { "voteThreshold": "simple-majority" }, - "checklist": [] - }, - { - "slug": "machtiging-boven-drempel", - "name": "Machtiging bestuur onderhoud boven drempel", - "description": "Machtiging aan het bestuur voor onderhoudsuitgaven boven de in het reglement bepaalde drempel.", - "context": "association", - "decisionType": "resolution", - "templateCategory": "authorisation-above-threshold", - "builtIn": true, - "proposedText": "De vergadering machtigt het bestuur tot het aangaan van de onderhoudsverplichting {omschrijving} voor een bedrag van {bedrag}, welk bedrag de reglementaire drempel overschrijdt.", - "regulationSource": "MR 2017 art. 56 lid 5", - "votingRule": { "voteThreshold": "qualified-majority-two-thirds" }, - "quorumRule": "2/3 (MR 2017 art. 56 lid 5)", - "checklist": [] - }, - { - "slug": "wijziging-huishoudelijk-reglement", - "name": "Wijziging huishoudelijk reglement", - "description": "Wijziging van het huishoudelijk reglement van de vereniging van eigenaars.", - "context": "association", - "decisionType": "resolution", - "templateCategory": "amendment-internal-regulations", - "builtIn": true, - "proposedText": "De vergadering besluit het huishoudelijk reglement te wijzigen conform het aangeboden voorstel {omschrijving}.", - "regulationSource": "MR 2017 art. 60", - "votingRule": { "voteThreshold": "qualified-majority-two-thirds" }, - "checklist": [] - } - ], - "vve-configuration": [ - { - "slug": "vve-parkstaete-configuratie", - "governanceBody": "vve-parkstaete", - "modelRegulation": "modelreglement-2017", - "modelReglementVersion": "2017", - "fractionDenominator": 10000, - "deedOfDivisionDocument": "splitsingsakte-vve-parkstaete", - "majorityOverrides": [ - { - "decisionCategory": "amendment-internal-regulations", - "templateCategory": "amendment-internal-regulations", - "voteThreshold": "qualified-majority-three-quarters", - "quorumFraction": null, - "deedArticle": "splitsingsakte VvE Parkstaete art. 62" - } - ] - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/lib/Settings/register.d/69-approval-routes.json b/lib/Settings/register.d/69-approval-routes.json index 170d2a07e..6940bfb4d 100644 --- a/lib/Settings/register.d/69-approval-routes.json +++ b/lib/Settings/register.d/69-approval-routes.json @@ -1,53 +1,6 @@ { "x-openregister": { - "seedData": { - "description": "Approval-route schema-declaration fragment (ADR-037 additive pattern; OpenSpec change approval-routes). Declares ApprovalRoute — the reusable template a sign-off sequence is instantiated FROM — and ApprovalAction, the append-only record of what each actor did. The travelling instance stays DecisionStage, which already models one decision's stages; this fragment adds the two things it lacked, a template to come from and a trail of actions against it. NOTE: 'routed' here means routed for SIGN-OFF. routedDocumentsJoin.js routes documents onto a meeting agenda and is a different concept entirely.", - "objects": { - "approval-route": [ - { - "slug": "collegeadvies-standaard", - "name": "Collegeadvies — standaard parafering", - "subjectType": "collegeadvies", - "isDefault": true, - "description": "Advies, twee paraferingen en een accordering. The shape a Dutch collegeadvies travels before it reaches the college.", - "steps": [ - { - "order": 1, - "stageType": "advisory", - "actorType": "role", - "actor": "juridisch-adviseur", - "mandatory": true, - "label": "Juridisch advies" - }, - { - "order": 2, - "stageType": "endorsement", - "actorType": "role", - "actor": "afdelingshoofd", - "mandatory": true, - "label": "Parafering afdelingshoofd" - }, - { - "order": 3, - "stageType": "endorsement", - "actorType": "role", - "actor": "concerncontroller", - "mandatory": false, - "label": "Parafering concerncontrol" - }, - { - "order": 4, - "stageType": "decisive", - "actorType": "role", - "actor": "gemeentesecretaris", - "mandatory": true, - "label": "Accordering gemeentesecretaris" - } - ] - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { @@ -59,7 +12,10 @@ "description": "A REUSABLE sign-off route: an ordered sequence of actors a subject travels for approval. Independent of any one subject — it describes a sequence to be travelled, and the travelling instance is DecisionStage. Distinct from DecisionTemplate/ProcessTemplate, which answer a different question: what STATES a decision may be in and how it moves between them. A route answers WHO signs, in what order.", "x-schema-org": "schema:HowTo", "type": "object", - "required": ["name", "steps"], + "required": [ + "name", + "steps" + ], "properties": { "name": { "title": "Name", @@ -95,7 +51,10 @@ "description": "The ordered steps. Copied into DecisionStage rows at instantiation, so editing a route never changes a route already in flight.", "items": { "type": "object", - "required": ["order", "stageType"], + "required": [ + "order", + "stageType" + ], "properties": { "order": { "title": "Order", @@ -106,13 +65,23 @@ "stageType": { "title": "Stage type", "type": "string", - "enum": ["preparatory", "advisory", "endorsement", "decisive", "ratifying"], + "enum": [ + "preparatory", + "advisory", + "endorsement", + "decisive", + "ratifying" + ], "description": "What the step is for. `endorsement` is the parafering case: a sign-off that is not itself the decision." }, "actorType": { "title": "Actor type", "type": "string", - "enum": ["person", "body", "role"], + "enum": [ + "person", + "body", + "role" + ], "default": "role", "description": "How `actor` resolves. `role` is resolved by the consuming context at instantiation; `person` and `body` name a stored object directly." }, @@ -145,7 +114,12 @@ "description": "An APPEND-ONLY record of what one actor did at one step of a sign-off route. Many rows per step: an advice, a return, a re-submission, a delegate acting under mandate. Never overwritten, and never deleted when a route is returned to an earlier step — a DecisionStage holds where a route IS, and these hold what happened, including the attempts a return undid. Collapsing the two loses exactly the history that makes a sign-off auditable.", "x-schema-org": "schema:Action", "type": "object", - "required": ["subject", "step", "actor", "action"], + "required": [ + "subject", + "step", + "actor", + "action" + ], "properties": { "subject": { "title": "Subject", @@ -171,7 +145,10 @@ "actorType": { "title": "Actor type", "type": "string", - "enum": ["user", "delegate"], + "enum": [ + "user", + "delegate" + ], "default": "user", "description": "Whether the actor acted for themselves or under a mandate for someone else." }, @@ -188,7 +165,13 @@ "action": { "title": "Action", "type": "string", - "enum": ["approved", "endorsed", "advised", "returned", "skipped"], + "enum": [ + "approved", + "endorsed", + "advised", + "returned", + "skipped" + ], "description": "What was done. `returned` sends the route back to an earlier step; every other value completes the current one." }, "returnToStep": { diff --git a/lib/Settings/register.d/70-configurable-types.json b/lib/Settings/register.d/70-configurable-types.json index fd2302b24..065a503f5 100644 --- a/lib/Settings/register.d/70-configurable-types.json +++ b/lib/Settings/register.d/70-configurable-types.json @@ -5,388 +5,7 @@ "description": "Register fragment for the configurable-types-domain-model change (ADR-037). Introduces the TYPE layer: MeetingType, AgendaItemType, PositionType, PositionHold and GovernanceBodyComposition, plus additive `type` references on Meeting, AgendaItem and Decision and the competence fields on DecisionTemplate. See openspec/changes/configurable-types-domain-model/design.md for why an enum was the wrong escape hatch and what is retired as a consequence." }, "x-openregister": { - "seedData": { - "description": "Seed objects for the configurable-types-domain-model acceptance scenario: gremia Management team and Development team, a gremium Pub quiz COMPOSED OF BOTH via two direct compositions, a Pub quiz night MeetingType on the Pub quiz, a votable Quiz question AgendaItemType, one pub quiz meeting and three quiz questions with voting rounds. References resolve by slug against objects in this same fragment. Deliberately English and domain-neutral: it demonstrates that the model is not council-specific, which is the whole claim of the change.", - "objects": { - "governance-body": [ - { - "slug": "management-team-conduction", - "name": "Management team", - "bodyType": "operational", - "domain": "operations", - "votingDefault": "for-against-abstain", - "active": true, - "termStart": "2026-01-01T00:00:00Z", - "id": "c7d10000-0000-4000-a000-000000000001", - "uuid": "c7d10000-0000-4000-a000-000000000001" - }, - { - "slug": "development-team-conduction", - "name": "Development team", - "bodyType": "operational", - "domain": "operations", - "votingDefault": "for-against-abstain", - "active": true, - "termStart": "2026-01-01T00:00:00Z", - "id": "c7d10000-0000-4000-a000-000000000002", - "uuid": "c7d10000-0000-4000-a000-000000000002" - }, - { - "slug": "pub-quiz-conduction", - "name": "Pub quiz", - "bodyType": "operational", - "domain": "operations", - "votingDefault": "for-against-abstain", - "active": true, - "termStart": "2026-01-01T00:00:00Z", - "id": "c7d10000-0000-4000-a000-000000000003", - "uuid": "c7d10000-0000-4000-a000-000000000003" - } - ], - "governance-body-composition": [ - { - "slug": "composition-pub-quiz-management-team", - "composite": "c7d10000-0000-4000-a000-000000000003", - "component": "c7d10000-0000-4000-a000-000000000001", - "compositionType": "direct", - "accessionDate": "2026-01-01", - "label": "Management team plays" - }, - { - "slug": "composition-pub-quiz-development-team", - "composite": "c7d10000-0000-4000-a000-000000000003", - "component": "c7d10000-0000-4000-a000-000000000002", - "compositionType": "direct", - "accessionDate": "2026-01-01", - "label": "Development team plays" - } - ], - "position-type": [ - { - "slug": "position-pub-quiz-quizmaster", - "name": "Quizmaster", - "governanceBody": "c7d10000-0000-4000-a000-000000000003", - "key": "quizmaster", - "seats": 1, - "order": 1, - "allowedHoldTypes": [ - "regular", - "interim" - ], - "termDurationMonths": 12, - "maxConsecutiveTerms": 3, - "reappointable": true, - "active": true, - "description": "Runs the quiz and rules on disputed answers. Demonstrates a position declared by its own gremium: the Management team has no quizmaster unless it declares one.", - "id": "c7d10000-0000-4000-a000-000000000011", - "uuid": "c7d10000-0000-4000-a000-000000000011" - }, - { - "slug": "position-management-team-chair", - "name": "Chair", - "governanceBody": "c7d10000-0000-4000-a000-000000000001", - "key": "chair", - "seats": 1, - "order": 1, - "allowedHoldTypes": [ - "regular", - "interim", - "acting" - ], - "termDurationMonths": 24, - "maxConsecutiveTerms": 2, - "reappointable": true, - "active": true, - "description": "Chairs the management team. Its allowedHoldTypes admit an interim; the quizmaster's do not admit 'acting' — hold types are configured per position, not globally.", - "id": "c7d10000-0000-4000-a000-000000000012", - "uuid": "c7d10000-0000-4000-a000-000000000012" - } - ], - "agenda-item-type": [ - { - "slug": "agenda-item-type-quiz-question", - "name": "Quiz question", - "owningBody": "c7d10000-0000-4000-a000-000000000003", - "votable": true, - "order": 1, - "isDraft": false, - "active": true, - "initialLifecycle": "open", - "lifecycleStates": [ - "open", - "voting", - "scored" - ], - "description": "A question the assembled teams vote on. Votable, so it carries a voting round; owned by the Pub quiz body.", - "fields": [ - { - "key": "correctAnswer", - "label": "Correct answer", - "fieldType": "string", - "required": false - }, - { - "key": "points", - "label": "Points", - "fieldType": "number", - "required": false - } - ], - "id": "c7d10000-0000-4000-a000-000000000021", - "uuid": "c7d10000-0000-4000-a000-000000000021" - }, - { - "slug": "agenda-item-type-quiz-round-opening", - "name": "Round opening", - "owningBody": "c7d10000-0000-4000-a000-000000000003", - "votable": false, - "order": 0, - "isDraft": false, - "active": true, - "initialLifecycle": "open", - "description": "Non-votable housekeeping item — proves a meeting type admits more than one item kind.", - "id": "c7d10000-0000-4000-a000-000000000022", - "uuid": "c7d10000-0000-4000-a000-000000000022" - } - ], - "meeting-type": [ - { - "slug": "meeting-type-pub-quiz-night", - "name": "Pub quiz night", - "governanceBody": "c7d10000-0000-4000-a000-000000000003", - "allowedAgendaItemTypes": [ - "c7d10000-0000-4000-a000-000000000022", - "c7d10000-0000-4000-a000-000000000021" - ], - "defaultQuorum": 4, - "defaultQuorumRule": "majority", - "defaultVotingRule": "for-against-abstain", - "defaultVoteThreshold": "simple-majority", - "defaultDurationMinutes": 90, - "initialLifecycle": "scheduled", - "isPublic": false, - "isDraft": false, - "validFrom": "2026-01-01", - "active": true, - "description": "The Pub quiz body's own meeting kind. It exists in no enum anywhere in decidiq — that is the point: a gremium defined its own meeting type at runtime, with zero code changed.", - "id": "c7d10000-0000-4000-a000-000000000031", - "uuid": "c7d10000-0000-4000-a000-000000000031" - } - ], - "meeting": [ - { - "slug": "pub-quiz-night-2026-09", - "title": "Pub quiz — September 2026", - "type": "c7d10000-0000-4000-a000-000000000031", - "governanceBody": "c7d10000-0000-4000-a000-000000000003", - "meetingType": "regular", - "scheduledDate": "2026-09-18T19:30:00Z", - "endDate": "2026-09-18T21:00:00Z", - "location": "Conduction HQ, kantine", - "meetingMode": "in-person", - "lifecycle": "scheduled", - "quorumRequired": 4, - "isPublic": false, - "id": "c7d10000-0000-4000-a000-000000000041", - "uuid": "c7d10000-0000-4000-a000-000000000041" - } - ], - "agenda-item": [ - { - "slug": "pub-quiz-2026-09-opening", - "title": "Welcome and rules", - "type": "c7d10000-0000-4000-a000-000000000022", - "itemType": "informational", - "orderNumber": 1, - "estimatedDuration": 5, - "meeting": "c7d10000-0000-4000-a000-000000000041", - "description": "The quizmaster opens the evening." - }, - { - "slug": "pub-quiz-2026-09-q1", - "title": "Which team ships more Friday deploys?", - "type": "c7d10000-0000-4000-a000-000000000021", - "itemType": "decision", - "orderNumber": 2, - "estimatedDuration": 10, - "meeting": "c7d10000-0000-4000-a000-000000000041", - "description": "Votable quiz question. The teams present are the Management team and the Development team, resolved through the Pub quiz body's two direct compositions — nobody was added to the Pub quiz by hand.", - "id": "c7d10000-0000-4000-a000-000000000042", - "uuid": "c7d10000-0000-4000-a000-000000000042" - }, - { - "slug": "pub-quiz-2026-09-q2", - "title": "Should the next quiz be held off-site?", - "type": "c7d10000-0000-4000-a000-000000000021", - "itemType": "decision", - "orderNumber": 3, - "estimatedDuration": 10, - "meeting": "c7d10000-0000-4000-a000-000000000041", - "description": "Votable quiz question.", - "id": "c7d10000-0000-4000-a000-000000000043", - "uuid": "c7d10000-0000-4000-a000-000000000043" - }, - { - "slug": "pub-quiz-2026-09-q3", - "title": "Is a tie broken by the quizmaster?", - "type": "c7d10000-0000-4000-a000-000000000021", - "itemType": "decision", - "orderNumber": 4, - "estimatedDuration": 10, - "meeting": "c7d10000-0000-4000-a000-000000000041", - "description": "Votable quiz question.", - "id": "c7d10000-0000-4000-a000-000000000044", - "uuid": "c7d10000-0000-4000-a000-000000000044" - } - ], - "voting-round": [ - { - "slug": "pub-quiz-2026-09-q1-vote", - "votingMethod": "for-against-abstain", - "isSecret": false, - "voteThreshold": "simple-majority", - "abstentionHandling": "exclude", - "tieBreakRule": "chair-decides", - "openedAt": "2026-09-18T19:40:00Z", - "id": "c7d10000-0000-4000-a000-000000000061", - "uuid": "c7d10000-0000-4000-a000-000000000061" - }, - { - "slug": "pub-quiz-2026-09-q2-vote", - "votingMethod": "for-against-abstain", - "isSecret": false, - "voteThreshold": "simple-majority", - "abstentionHandling": "exclude", - "tieBreakRule": "chair-decides", - "openedAt": "2026-09-18T19:50:00Z", - "id": "c7d10000-0000-4000-a000-000000000062", - "uuid": "c7d10000-0000-4000-a000-000000000062" - }, - { - "slug": "pub-quiz-2026-09-q3-vote", - "votingMethod": "show-of-hands", - "isSecret": false, - "voteThreshold": "simple-majority", - "abstentionHandling": "count", - "tieBreakRule": "chair-decides", - "openedAt": "2026-09-18T20:00:00Z", - "id": "c7d10000-0000-4000-a000-000000000063", - "uuid": "c7d10000-0000-4000-a000-000000000063" - } - ], - "decision-template": [ - { - "slug": "decision-type-quiz-answer", - "id": "c7d10000-0000-4000-a000-000000000051", - "uuid": "c7d10000-0000-4000-a000-000000000051", - "name": "Quiz answer", - "description": "A quiz question put to the assembled teams. Demonstrates REQ-CTM-003/004: the decision references this TYPE rather than copying it, and the type names the gremium competent to take it.", - "decisionType": "motion", - "context": "operations", - "builtIn": false, - "competentBody": "c7d10000-0000-4000-a000-000000000003", - "competentPositionTypes": [ - "c7d10000-0000-4000-a000-000000000011" - ], - "quorumRequired": true, - "quorumRule": "majority", - "allowDecideWithoutVote": false, - "initialState": "proposed" - } - ], - "decision": [ - { - "slug": "pub-quiz-2026-09-decision-q1", - "id": "c7d10000-0000-4000-a000-000000000071", - "uuid": "c7d10000-0000-4000-a000-000000000071", - "title": "Which team ships more Friday deploys?", - "text": "Resolution recorded for quiz question 1 of the September 2026 pub quiz.", - "decisionType": "motion", - "type": "c7d10000-0000-4000-a000-000000000051", - "agendaItem": "c7d10000-0000-4000-a000-000000000042", - "lifecycle": "voting", - "votingOrder": 1, - "voteType": "named", - "voteThreshold": "simple-majority" - }, - { - "slug": "pub-quiz-2026-09-decision-q2", - "id": "c7d10000-0000-4000-a000-000000000072", - "uuid": "c7d10000-0000-4000-a000-000000000072", - "title": "Should the next quiz be held off-site?", - "text": "Resolution recorded for quiz question 2 of the September 2026 pub quiz.", - "decisionType": "motion", - "type": "c7d10000-0000-4000-a000-000000000051", - "agendaItem": "c7d10000-0000-4000-a000-000000000043", - "lifecycle": "voting", - "votingOrder": 2, - "voteType": "named", - "voteThreshold": "simple-majority" - }, - { - "slug": "pub-quiz-2026-09-decision-q3", - "id": "c7d10000-0000-4000-a000-000000000073", - "uuid": "c7d10000-0000-4000-a000-000000000073", - "title": "Is a tie broken by the quizmaster?", - "text": "Resolution recorded for quiz question 3 of the September 2026 pub quiz.", - "decisionType": "motion", - "type": "c7d10000-0000-4000-a000-000000000051", - "agendaItem": "c7d10000-0000-4000-a000-000000000044", - "lifecycle": "voting", - "votingOrder": 3, - "voteType": "named", - "voteThreshold": "simple-majority" - } - ], - "decision-stage": [ - { - "slug": "pub-quiz-2026-09-stage-q1", - "id": "c7d10000-0000-4000-a000-000000000081", - "uuid": "c7d10000-0000-4000-a000-000000000081", - "sequence": 1, - "mandatory": true, - "stageType": "vote", - "status": "in-progress", - "method": "vote", - "decisionMakerType": "body", - "label": "Vote on question 1", - "decision": "c7d10000-0000-4000-a000-000000000071", - "assignedBody": "c7d10000-0000-4000-a000-000000000003", - "votingRound": "c7d10000-0000-4000-a000-000000000061" - }, - { - "slug": "pub-quiz-2026-09-stage-q2", - "id": "c7d10000-0000-4000-a000-000000000082", - "uuid": "c7d10000-0000-4000-a000-000000000082", - "sequence": 1, - "mandatory": true, - "stageType": "vote", - "status": "in-progress", - "method": "vote", - "decisionMakerType": "body", - "label": "Vote on question 2", - "decision": "c7d10000-0000-4000-a000-000000000072", - "assignedBody": "c7d10000-0000-4000-a000-000000000003", - "votingRound": "c7d10000-0000-4000-a000-000000000062" - }, - { - "slug": "pub-quiz-2026-09-stage-q3", - "id": "c7d10000-0000-4000-a000-000000000083", - "uuid": "c7d10000-0000-4000-a000-000000000083", - "sequence": 1, - "mandatory": true, - "stageType": "vote", - "status": "in-progress", - "method": "vote", - "decisionMakerType": "body", - "label": "Vote on question 3", - "decision": "c7d10000-0000-4000-a000-000000000073", - "assignedBody": "c7d10000-0000-4000-a000-000000000003", - "votingRound": "c7d10000-0000-4000-a000-000000000063" - } - ] - } - } + "_seedDataNote": "Seed objects MOVED to lib/Settings/profiles/*.json (OpenSpec change seed-profiles). A register.d fragment declares SCHEMAS ONLY, so installing this app plants zero objects. The examples that used to live here are now part of an example set an operator picks in the first-time setup wizard, which is the only thing that imports them." }, "components": { "schemas": { diff --git a/openspec/changes/seed-profiles/proposal.md b/openspec/changes/seed-profiles/proposal.md new file mode 100644 index 000000000..2a17d2cfc --- /dev/null +++ b/openspec/changes/seed-profiles/proposal.md @@ -0,0 +1,69 @@ +--- +kind: code +--- + +# Proposal: seed-profiles + +## Summary + +Stop planting example data on install. Move the 334 seed objects out of the register fragments into **example sets**, one per kind of organisation, and let the operator pick which one to load in the first-time setup wizard. + +## Motivation + +Installing this app plants 334 objects nobody asked for. + +`SettingsService::loadConfiguration()` merges `decidesk_register.json` with all 26 `register.d` fragments, and every one of them carried its own `x-openregister.seedData.objects`. The `InitializeSettings` repair step runs that merge, so a fresh install seeds a Gemeenteraad Amsterdam, a VvE Zeewaarts, a pub quiz, five ACME B.V. bodies and eight placeholder TOOI mappings into the operator's register. A municipality gets the VvE data. A VvE gets the council data. Nobody chose any of it. + +Measured on the tree at 2026-08-30: + +| | | +|---|---| +| seed objects imported on install | **334** (118 base + 216 across 26 fragments) | +| of those the operator chose | **0** | +| datasets the setup wizard offered | 1, and a **different** one | + +The wizard already offered a demo dataset (`decidiq_mock_register.json`) whose own step text says "Skip this on a production install". By the time an operator reads that sentence, 334 objects are already in their register. The advice was true and useless. + +## Affected Projects + +- [x] Project: `decidiq` — this change. + +## Scope + +**In scope.** Splitting the shipped seeds into four example sets, a service that lists and imports one, the two wizard steps that ask and load, and authoring a works-council set that did not previously exist. + +**Out of scope.** Generalising the domain-bound schemas themselves (`VveConfiguration`, `Raadsinformatiebrief`, `WooCategorieMapping` and ~32 others). That is the next change in this chain; this one moves data without renaming anything, so the diff stays reviewable. + +## What the split had to solve + +The seeds are cross-referenced by slug, and a naive partition would leave dangling references. Building the reference graph showed one connected component of 170 objects tangling municipal, corporate and association bodies together, so a partition was impossible. + +The resolution: **a set is a closure, not a partition.** Each set is anchored on the governance bodies that belong to it, then closed over outbound references, so every reference resolves inside the set that carries it. Sets may overlap, and 15 objects do. Verified mechanically: 334 of 334 objects classified, zero dangling references, zero orphans. + +## Defects this surfaced and fixes + +Validating every seed against its schema turned up ten pre-existing defects, all fixed here: + +- **`regulation` matched no decidiq schema.** Three seeds keyed on `regulation`; the app's schema slug is `regeling`. Because `importSeedData()` resolves a schema slug cross-app with multitenancy off, `regulation` resolves to **learniq's** schema. Re-keyed to `regeling`. +- **`Regeling.status` was required, lifecycle-driven and never declared.** `x-openregister-lifecycle` names `status` as its field and `required` lists it, but `properties` did not, so OpenRegister created no magic-table column. Verified on a live instance: `oc_openregister_table_21_262` carried every other property and no `status` column, which means the declared `in-preparation → adopted → in-effect → lapsed` map could never advance. Property added. +- **Six invalid enum values** on the pub-quiz `decision-stage` seeds (`stageType: vote`, `status: in-progress`). +- **Two governance bodies missing the required `domain`.** +- **The works-council seeds described a city council.** All three WOR consultation requests carried `governanceBody: gemeenteraad-amsterdam`, a null-UUID `director`, and a raadsvergadering as their overlegvergadering. Rewritten as a real 45-object set: an ondernemingsraad at ACME B.V. with members, an overlegvergadering, two adviesaanvragen, an instemmingsverzoek under the WOR, and an achterbanraadpleging. + +## Why the descriptor declares no register + +An example set carries `@self.configuration/register/schema` on every object and declares **no** `components.registers`. + +That is load-bearing, not stylistic. `ImportHandler::importRegister()` calls `setApplication($appId)` unconditionally when it updates an existing register, so a descriptor that declared `decidiq` would re-point the register at the profile's config id and hydrate over its `authorization` block — the baseline that stops any authenticated user rewriting another body's decisions. Verified against a live instance: importing this shape left `application=decidiq`, the version, and the authorization hash byte-identical, and imported 45 objects. + +The files also live in a **subdirectory**, because `RegisterDescriptorService` scans `lib/Settings/*.json` non-recursively and indexes by declared register slug. Four profiles in `lib/Settings` would collide with each other and with the app's own register. + +## Why two wizard steps + +`CnSetupWizard::runAction()` posts to `/api/setup/action/{action}` with no body, so an action cannot carry the answer. A `choice` step records which set (via `POST /api/setup/config`), and the `run-action` step that follows reads it back and imports it. + +ADR-111 requires the schema-generated mock to stay on offer. Rather than ask twice about the same thing, it is one option in the same choice. + +## Next step + +Chain link 2 generalises the VvE schemas into per-body governance configuration, and adds the `Decision templates` settings page that the unified 84-row `decision-template` schema still has no surface for. diff --git a/openspec/changes/seed-profiles/specs/seed-profiles/spec.md b/openspec/changes/seed-profiles/specs/seed-profiles/spec.md new file mode 100644 index 000000000..aaab43bd0 --- /dev/null +++ b/openspec/changes/seed-profiles/specs/seed-profiles/spec.md @@ -0,0 +1,139 @@ +# seed-profiles Specification + +**Status**: planned +**Scope**: decidiq +**OpenSpec changes**: +- [seed-profiles](../../changes/seed-profiles/) + +## Purpose + +Example data an operator chooses, instead of example data an install imposes. The app ships one descriptor per kind of organisation; the first-time setup wizard asks which one, and imports only that. + +**Standards**: ADR-042 (first-time setup contract), ADR-111 (demo data), ADR-037 (additive register fragments) + +## ADDED Requirements + +### Requirement: Installing the app plants no objects + +A register fragment SHALL declare schemas only. `decidesk_register.json` and every file in `lib/Settings/register.d/` SHALL NOT carry `x-openregister.seedData`. + +Installing or upgrading the app SHALL therefore create registers and schemas and zero objects. An operator who never opens the wizard SHALL find an empty app, not somebody else's organisation. + +#### Scenario: A fresh install seeds nothing + +- **WHEN** the app is installed and `SettingsService::loadConfiguration()` runs +- **THEN** the merged configuration carries no `x-openregister.seedData` key +- **AND** no example object is created + +#### Scenario: The seeds still ship + +- **WHEN** the example sets are read from `lib/Settings/profiles/` +- **THEN** every object formerly seeded by a register fragment is present in at least one set + +### Requirement: List example sets + +The system SHALL expose the example sets it ships, each carrying `id`, `label`, `description` and `objectCount`, ordered by the `order` its descriptor declares. + +The list SHALL be read from the descriptors on disk rather than from a list in code, so a set that ships without being offered is impossible. + +`GET /api/setup/status` SHALL include the list as `profiles`. + +#### Scenario: Every shipped set is offered + +- **WHEN** an administrator requests the setup status +- **THEN** the response lists one entry per descriptor in `lib/Settings/profiles/` +- **AND** each entry names a non-empty label and a positive object count + +#### Scenario: The generated set is offered only when it ships + +- **WHEN** `decidiq_mock_register.json` is absent +- **THEN** the `generated` option is not offered +- **AND** the wizard does not present an import that cannot run + +### Requirement: Record the chosen example set + +`POST /api/setup/config` SHALL accept `example_profile` and persist it, and SHALL be admin-only. + +The endpoint SHALL read exactly one named key from the request and SHALL NOT write a caller-supplied key. The app's own settings share the appconfig namespace, including `voter_token_secret`, the HMAC key signing every voting token and mail-reply link. + +A value that names neither a shipped set nor `none` SHALL be rejected with 400 and SHALL NOT be stored. + +#### Scenario: A pick is persisted + +- **WHEN** an administrator posts `example_profile: municipality` +- **THEN** the value is stored and echoed back + +#### Scenario: An unknown set is refused + +- **WHEN** an administrator posts an id no descriptor declares +- **THEN** the response is 400 and nothing is stored + +### Requirement: Import one example set + +The system SHALL import the chosen set and report how many objects it carried. + +The import SHALL be idempotent: running it twice SHALL add nothing, because OpenRegister matches an existing object by slug before creating one. + +A failure SHALL be reported to the operator and SHALL NOT record the step as decided. An operator who asked for example data and received none must be able to ask again. + +Running the action with no set chosen SHALL be refused with 400 rather than defaulting to one. + +#### Scenario: Loading reports what landed + +- **WHEN** an administrator runs `load-example-set` after choosing a set +- **THEN** the response names a non-zero object count + +#### Scenario: Loading twice adds nothing + +- **WHEN** the action runs a second time +- **THEN** it succeeds and the object count in the register is unchanged + +#### Scenario: Loading without a choice refuses + +- **WHEN** the action runs and no set has been chosen +- **THEN** the response is 400 and no object is created + +#### Scenario: A failed import leaves the step open + +- **WHEN** the import throws +- **THEN** the response reports the failure +- **AND** the step is not recorded as decided + +### Requirement: Declining is an answer + +`none` SHALL be a selectable value. Choosing it SHALL mark both the choice step and the load step done without importing anything. + +A step that can never be marked done reopens the wizard over every page, so "no thanks" has to be expressible. + +#### Scenario: Choosing none closes the wizard + +- **WHEN** an administrator chooses `none` +- **THEN** both setup steps report `done: true` +- **AND** no object is created + +### Requirement: An example set never rewrites the register + +An example-set descriptor SHALL NOT declare `components.registers`. Every seed object SHALL carry `@self` naming the configuration, register and schema it belongs to. + +`ImportHandler::importRegister()` calls `setApplication($appId)` unconditionally when it updates an existing register, so a descriptor that declared the register would re-point it at the profile's configuration id and hydrate over its `authorization` baseline. + +Descriptors SHALL live in `lib/Settings/profiles/`, not `lib/Settings/`, because `RegisterDescriptorService` scans the latter non-recursively and indexes descriptors by declared register slug. + +#### Scenario: Importing a set leaves the register untouched + +- **WHEN** an example set is imported +- **THEN** the register's `application`, version and `authorization` are unchanged + +#### Scenario: Every seed resolves its own register + +- **WHEN** a shipped example set is read +- **THEN** every object carries `@self` naming the `decidiq` register and its own schema slug + +### Requirement: A set identifier cannot escape the profile directory + +The set id arrives from an HTTP request. The system SHALL resolve a descriptor by matching the id declared INSIDE each file, and SHALL NOT build a path by concatenating the id. + +#### Scenario: A traversal id resolves to nothing + +- **WHEN** an id such as `../../config/config` is submitted +- **THEN** it is not recognised as a set and the import throws diff --git a/openspec/changes/seed-profiles/tasks.md b/openspec/changes/seed-profiles/tasks.md new file mode 100644 index 000000000..9c091bff4 --- /dev/null +++ b/openspec/changes/seed-profiles/tasks.md @@ -0,0 +1,31 @@ +# Tasks: seed-profiles + +## 1. Split the shipped seeds into example sets + +- [x] 1.1 Build the seed reference graph and classify all 334 objects by the governance body they reach +- [x] 1.2 Close each set over outbound references so no reference dangles +- [x] 1.3 Write `lib/Settings/profiles/{municipality,association,corporate,works-council}.json` +- [x] 1.4 Strip `x-openregister.seedData` from `decidesk_register.json` and all 26 `register.d` fragments +- [x] 1.5 Verify the round trip: every object present, no content changed, nothing but `seedData` removed + +## 2. Fix the defects validation surfaced + +- [x] 2.1 Re-key the three `regulation` seeds onto `regeling`, the app's own schema slug +- [x] 2.2 Declare `Regeling.status`, which was required and lifecycle-driven but had no property and no column +- [x] 2.3 Correct six invalid enum values on the pub-quiz `decision-stage` seeds +- [x] 2.4 Add the required `domain` to two governance bodies +- [x] 2.5 Author a real works-council set, replacing seeds that described a city council + +## 3. Serve and import the sets + +- [x] 3.1 `SeedProfileService`: list from disk, resolve by declared id, import one, refuse traversal +- [x] 3.2 `SetupController`: report both steps and the set list; add `saveConfig`; dispatch `load-example-set` +- [x] 3.3 Route `POST /api/setup/config` +- [x] 3.4 Manifest: a `choice` step and a `run-action` step, with `none` and the ADR-111 generated set as options + +## 4. Prove it + +- [x] 4.1 Unit tests for the service, including traversal and the manifest-drift guard +- [x] 4.2 Retarget the register seed assertions at the profiles; invert the `@self` rule +- [x] 4.3 Rewrite the setup e2e spec for the choice-then-load contract +- [x] 4.4 Verify on a live instance: 45 objects imported, register row byte-identical, re-run adds nothing diff --git a/src/manifest.json b/src/manifest.json index d2ac80053..0b1a3f72c 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -11,12 +11,46 @@ "body": "A short setup to get this app ready. Nothing here is required; you can close it and come back later." }, { - "id": "demo-data", + "id": "example-set", + "type": "choice", + "title": "Which kind of organisation is this for?", + "configKey": "example_profile", + "required": false, + "body": "Pick the organisation this app runs for and you get a worked example of it: bodies, meetings, decisions and templates that fit. Installing the app plants nothing on its own, so this is the only step that adds data. Choose \"None\" on a production install.", + "options": [ + { + "value": "none", + "label": "None, I will set this up myself" + }, + { + "value": "municipality", + "label": "Municipality" + }, + { + "value": "association", + "label": "Association or VvE" + }, + { + "value": "corporate", + "label": "Company board" + }, + { + "value": "works-council", + "label": "Works council" + }, + { + "value": "generated", + "label": "Every schema, generated values" + } + ] + }, + { + "id": "load-example-set", "type": "run-action", - "action": "install-demo-data", - "title": "Demo data (optional)", + "action": "load-example-set", + "title": "Load the example data", "required": false, - "body": "Load a small example dataset so the lists, detail pages and dashboards show a working product straight away. The data is obviously sample data, it is safe to run more than once, and it can be removed afterwards. Skip this on a production install." + "body": "Loads the set you picked. The data is obviously sample data, it is safe to run more than once, and you can delete it afterwards." }, { "id": "done", diff --git a/tests/Unit/Controller/SetupControllerTest.php b/tests/Unit/Controller/SetupControllerTest.php index 5e16ec345..863c9d093 100644 --- a/tests/Unit/Controller/SetupControllerTest.php +++ b/tests/Unit/Controller/SetupControllerTest.php @@ -3,7 +3,7 @@ namespace Unit\Controller; use OCA\Decidiq\Controller\SetupController; -use OCA\Decidiq\Service\DemoDataService; +use OCA\Decidiq\Service\SeedProfileService; use OCP\IAppConfig; use OCP\IRequest; use PHPUnit\Framework\TestCase; @@ -18,46 +18,115 @@ * step that can never be marked done keeps the wizard open over every page — * so "the step is reported" and "a decision closes it" are the contract, not * incidental detail. + * + * The seed-profiles change split one question in two, because + * `CnSetupWizard::runAction()` posts no body: the `choice` step records WHICH + * example set, and the `run-action` step that follows imports it. */ class SetupControllerTest extends TestCase { private IAppConfig $appConfig; private LoggerInterface $logger; - private DemoDataService $demoData; + private SeedProfileService $seedProfiles; + private IRequest $request; private SetupController $controller; protected function setUp(): void { $this->appConfig = $this->createMock(IAppConfig::class); $this->logger = $this->createMock(LoggerInterface::class); - $this->demoData = $this->createMock(DemoDataService::class); + $this->seedProfiles = $this->createMock(SeedProfileService::class); + $this->request = $this->createMock(IRequest::class); $this->controller = new SetupController( - $this->createMock(IRequest::class), + $this->request, $this->appConfig, $this->logger, - $this->demoData + $this->seedProfiles ); } - public function testStatusReportsTheDemoDataStep(): void { + public function testStatusReportsBothExampleSetSteps(): void { $this->appConfig->method('getValueString')->willReturn(''); + $this->seedProfiles->method('listProfiles')->willReturn([]); $data = $this->controller->status()->getData(); // Absence is the defect this guards: a step the wizard is never told // about cannot be offered and cannot be completed. - $this->assertArrayHasKey('demo-data', $data['steps']); - $this->assertFalse($data['steps']['demo-data']['done']); + $this->assertArrayHasKey('example-set', $data['steps']); + $this->assertArrayHasKey('load-example-set', $data['steps']); + $this->assertFalse($data['steps']['example-set']['done']); + $this->assertFalse($data['steps']['load-example-set']['done']); // This app declares no REQUIRED step, so setup must never gate the app. $this->assertTrue($data['completed']); $this->assertSame(1, $data['version']); } - public function testStatusReportsTheStepDoneOnceDecided(): void { - $this->appConfig->method('getValueString')->willReturn('skipped'); + public function testStatusOffersTheSetsTheAppShips(): void { + $this->appConfig->method('getValueString')->willReturn(''); + $this->seedProfiles->method('listProfiles')->willReturn([ + ['id' => 'municipality', 'label' => 'Municipality', 'description' => '', 'objectCount' => 199], + ]); + + $data = $this->controller->status()->getData(); + + // The sets are read from disk, so a set that ships is always offered. + $this->assertSame('municipality', $data['profiles'][0]['id']); + } + + public function testChoosingNoneClosesTheLoadStepWithoutRunningIt(): void { + // 🔴 THE POINT OF THIS TEST. "None" is an ANSWER, not the absence of + // one. If picking it left the load step outstanding, the wizard would + // reopen over every page for an operator who has already said no. + $this->appConfig->method('getValueString') + ->willReturnCallback(static fn (string $app, string $key): string + => ($key === 'example_profile' ? 'none' : '')); + $this->seedProfiles->method('listProfiles')->willReturn([]); $data = $this->controller->status()->getData(); - $this->assertTrue($data['steps']['demo-data']['done']); + $this->assertTrue($data['steps']['example-set']['done']); + $this->assertTrue($data['steps']['load-example-set']['done']); + } + + public function testTheChoiceIsPersisted(): void { + $this->request->method('getParam')->willReturn('municipality'); + $this->seedProfiles->method('isKnown')->with('municipality')->willReturn(true); + + $this->appConfig->expects($this->once()) + ->method('setValueString') + ->with('decidiq', 'example_profile', 'municipality'); + + $data = $this->controller->saveConfig()->getData(); + + $this->assertTrue($data['success']); + $this->assertSame('municipality', $data['config']['example_profile']); + } + + public function testAnUnknownSetIsRejectedRatherThanStored(): void { + // Storing it would leave the load step pointing at a set that does not + // exist, so the failure would surface one step later with no clue why. + $this->request->method('getParam')->willReturn('atlantis'); + $this->seedProfiles->method('isKnown')->with('atlantis')->willReturn(false); + + $this->appConfig->expects($this->never())->method('setValueString'); + + $response = $this->controller->saveConfig(); + + $this->assertSame(400, $response->getStatus()); + $this->assertFalse($response->getData()['success']); + } + + public function testLoadingWithoutAChoiceRefusesRatherThanGuessing(): void { + // 🔴 NO SILENT DEFAULT. Guessing a set here would plant a municipality + // into an operator's register because they clicked Run one step early, + // which is the exact failure this change exists to remove. + $this->appConfig->method('getValueString')->willReturn(''); + $this->seedProfiles->expects($this->never())->method('install'); + + $response = $this->controller->runAction('load-example-set'); + + $this->assertSame(400, $response->getStatus()); + $this->assertFalse($response->getData()['success']); } public function testSkippingIsAnAnswerAndIsRecorded(): void { @@ -67,7 +136,7 @@ public function testSkippingIsAnAnswerAndIsRecorded(): void { ->method('setValueString') ->with('decidiq', 'demo_data_decided', 'skipped'); - $response = $this->controller->runAction('skip-demo-data'); + $response = $this->controller->runAction('skip-example-set'); $this->assertTrue($response->getData()['success']); } @@ -79,34 +148,36 @@ public function testUnknownActionIs404(): void { $this->assertFalse($response->getData()['success']); } - public function testInstallReportsHowMuchLanded(): void { - $this->demoData->method('install') - ->willReturn(['objects' => 30, 'registers' => 1, 'schemas' => 4]); + public function testLoadReportsHowMuchLanded(): void { + $this->appConfig->method('getValueString')->willReturn('municipality'); + $this->seedProfiles->method('install')->with('municipality') + ->willReturn(['objects' => 199, 'profile' => 'municipality']); $this->appConfig->expects($this->once()) ->method('setValueString') ->with('decidiq', 'demo_data_decided', 'installed'); - $data = $this->controller->runAction('install-demo-data')->getData(); + $data = $this->controller->runAction('load-example-set')->getData(); $this->assertTrue($data['success']); // A success message that names no count cannot be told apart from an // import that wrote nothing — the defect this programme already shipped. - $this->assertStringContainsString('30', $data['message']); + $this->assertStringContainsString('199', $data['message']); } - public function testAFailedInstallIsReportedAndLeavesTheStepUNDECIDED(): void { - $this->demoData->method('install') + public function testAFailedLoadIsReportedAndLeavesTheStepUNDECIDED(): void { + $this->appConfig->method('getValueString')->willReturn('municipality'); + $this->seedProfiles->method('install') ->willThrowException(new RuntimeException('OpenRegister is not installed.')); // 🔴 THE POINT OF THIS TEST. Recording the decision here would close the - // step for an operator who asked for demo data and received none: the + // step for an operator who asked for example data and received none: the // wizard would never offer it again, and nothing would have been // imported. $this->appConfig->expects($this->never())->method('setValueString'); $this->logger->expects($this->once())->method('error'); - $response = $this->controller->runAction('install-demo-data'); + $response = $this->controller->runAction('load-example-set'); $this->assertSame(500, $response->getStatus()); $this->assertFalse($response->getData()['success']); diff --git a/tests/Unit/RegisterJsonTest.php b/tests/Unit/RegisterJsonTest.php index 87f912ebc..aa6d248ad 100644 --- a/tests/Unit/RegisterJsonTest.php +++ b/tests/Unit/RegisterJsonTest.php @@ -75,6 +75,47 @@ protected function setUp(): void { }//end setUp() + /** + * Every example object this app ships, keyed by schema slug. + * + * 🔴 THE SEEDS MOVED OUT OF THE REGISTER, SO THESE ASSERTIONS FOLLOW THEM. + * Until the seed-profiles change, `decidesk_register.json` and its 26 + * `register.d` fragments each carried their own + * `x-openregister.seedData.objects`, and installing the app planted all 334 + * of them. They now live in `lib/Settings/profiles/*.json`, one file per + * example set, and nothing is planted until an operator picks one. A test + * that still read the register would report "no decision seeds" and be + * describing the intended state as a failure. + * + * The union across sets is the right subject here: these tests ask whether + * the app SHIPS demonstrable data for a schema, not which set carries it. + * + * @return array>> Objects per schema slug. + */ + private function profileSeeds(): array { + $files = glob(__DIR__ . '/../../lib/Settings/profiles/*.json'); + self::assertNotEmpty(actual: $files, message: 'App must ship at least one example set'); + + $merged = []; + foreach ($files as $file) { + $json = file_get_contents(filename: $file); + self::assertNotFalse(condition: $json, message: 'Example set must be readable: ' . basename($file)); + $data = json_decode(json: $json, associative: true, depth: 512, flags: JSON_THROW_ON_ERROR); + + foreach (($data['x-openregister']['seedData']['objects'] ?? []) as $slug => $objects) { + foreach ($objects as $object) { + // Sets overlap by design: a person can belong to a council and + // a company board alike, so de-duplicate on the slug that + // OpenRegister's own idempotency check uses. + $merged[$slug][($object['slug'] ?? spl_object_hash((object)$object))] = $object; + } + } + } + + return array_map(static fn (array $bySlug): array => array_values($bySlug), $merged); + + }//end profileSeeds() + /** * Test that the register JSON is valid OpenAPI 3.0.0 with x-openregister extensions. * @@ -468,10 +509,10 @@ public function testSeedDataPresent(): void { 'minutes', ]; - $seedObjects = ($this->register['x-openregister']['seedData']['objects'] ?? []); + $seedObjects = $this->profileSeeds(); self::assertNotEmpty( actual: $seedObjects, - message: 'Register must declare x-openregister.seedData.objects' + message: 'The example sets must declare x-openregister.seedData.objects' ); foreach ($coreSchemaSlugs as $slug) { @@ -483,12 +524,37 @@ public function testSeedDataPresent(): void { ); foreach ($seeds as $seed) { - // The importer takes register + schema from the import context, so a seed - // carries no @self envelope; its identity is a non-empty `slug` property. - self::assertArrayNotHasKey( + // 🔴 THIS ASSERTION USED TO SAY THE OPPOSITE, AND THE INVERSION IS + // THE WHOLE MECHANISM OF THE seed-profiles CHANGE. + // + // While the seeds lived in the app's own configuration, the + // importer took register + schema from the import context, so an + // @self envelope was redundant and the test forbade it. + // + // An example set declares NO `components.registers`, deliberately: + // ImportHandler::importRegister() calls setApplication($appId) + // unconditionally when it updates an existing register, so a + // profile that declared `decidiq` would re-point the register at + // that profile's config id and hydrate over its `authorization` + // baseline. With no register in the descriptor there is no import + // context to inherit, and importSeedDataObjects() would fall back + // to "register 0" and drop every object. @self is what resolves + // each object instead, and importSeedDataObjects() only consults + // `@self.register` / `@self.schema` when `@self.configuration` is + // also present, so all three are required rather than decorative. + // + // Verified on a live instance: this shape imported the objects and + // left application=decidiq, the version and the authorization block + // byte-identical. + self::assertArrayHasKey( key: '@self', array: $seed, - message: "Seed in '{$slug}' must not carry an @self envelope under seedData" + message: "Seed in '{$slug}' must carry an @self envelope so it resolves its own register" + ); + self::assertSame( + expected: ['configuration' => 'decidiq', 'register' => 'decidiq', 'schema' => $slug], + actual: $seed['@self'], + message: "Seed in '{$slug}' must resolve the decidiq register and its own schema" ); self::assertNotEmpty( actual: ($seed['slug'] ?? ''), @@ -513,8 +579,8 @@ public function testSeedDataPresent(): void { * @spec openspec/specs/decision-management/spec.md */ public function testDecisionSeedsRespectTerminalCompleteness(): void { - $seeds = ($this->register['x-openregister']['seedData']['objects']['decision'] ?? []); - self::assertNotEmpty(actual: $seeds, message: 'Register must seed decision objects'); + $seeds = ($this->profileSeeds()['decision'] ?? []); + self::assertNotEmpty(actual: $seeds, message: 'The example sets must seed decision objects'); $terminalStates = ['decided', 'enacted', 'archived']; $outcomeEnum = $this->schemas['Decision']['properties']['outcome']['enum']; @@ -822,7 +888,7 @@ public function testMeetingSchemaHasAnalyticsLeafAggregations(): void { */ public function testEngagementRecordHasSeedData(): void { // Keyed by schema slug under the seedData map — the location the importer reads. - $seeds = ($this->register['x-openregister']['seedData']['objects']['engagement-record'] ?? []); + $seeds = ($this->profileSeeds()['engagement-record'] ?? []); self::assertGreaterThanOrEqual( expected: 3, actual: count($seeds), diff --git a/tests/Unit/Service/SeedProfileServiceTest.php b/tests/Unit/Service/SeedProfileServiceTest.php new file mode 100644 index 000000000..578f65dab --- /dev/null +++ b/tests/Unit/Service/SeedProfileServiceTest.php @@ -0,0 +1,150 @@ +appManager = $this->createMock(IAppManager::class); + $this->appManager->method('getAppPath')->willReturn(dirname(__DIR__, 3)); + $this->demoData = $this->createMock(DemoDataService::class); + + $this->service = new SeedProfileService( + $this->appManager, + $this->createMock(ContainerInterface::class), + $this->createMock(LoggerInterface::class), + $this->demoData + ); + } + + public function testEveryShippedSetIsOffered(): void { + $this->demoData->method('isAvailable')->willReturn(false); + + $ids = array_column($this->service->listProfiles(), 'id'); + + // Read from disk rather than a list in code, so a set that ships without + // being offered is impossible by construction. + $this->assertSame(['municipality', 'association', 'corporate', 'works-council'], $ids); + } + + public function testSetsAreOfferedInTheirDeclaredOrder(): void { + $this->demoData->method('isAvailable')->willReturn(false); + + $profiles = $this->service->listProfiles(); + + $this->assertSame('municipality', $profiles[0]['id']); + // `order` is an implementation detail of the file, not of the offer. + $this->assertArrayNotHasKey('order', $profiles[0]); + $this->assertGreaterThan(0, $profiles[0]['objectCount']); + $this->assertNotSame('', $profiles[0]['label']); + } + + public function testTheGeneratedSetIsOfferedOnlyWhenItShips(): void { + // ADR-111 rule 2 keeps the schema-generated dataset on offer, but only + // when the descriptor is actually on disk: offering an import that + // cannot run is worse than not offering it. + $this->demoData->method('isAvailable')->willReturn(true); + $this->assertContains('generated', array_column($this->service->listProfiles(), 'id')); + + $absent = new SeedProfileService( + $this->appManager, + $this->createMock(ContainerInterface::class), + $this->createMock(LoggerInterface::class), + $this->stubDemoData(available: false) + ); + $this->assertNotContains('generated', array_column($absent->listProfiles(), 'id')); + } + + public function testAnUnknownSetIsNotKnown(): void { + $this->demoData->method('isAvailable')->willReturn(false); + + $this->assertTrue($this->service->isKnown('municipality')); + $this->assertFalse($this->service->isKnown('atlantis')); + } + + public function testInstallingAnUnknownSetThrowsRatherThanReturningNothing(): void { + $this->demoData->method('isAvailable')->willReturn(false); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('No example set is called "atlantis".'); + + $this->service->install('atlantis'); + } + + public function testASetIdCannotEscapeTheProfileDirectory(): void { + // 🔴 THE POINT OF THIS TEST. The id arrives from an HTTP request. If the + // path were built by concatenating it, `../../config/config` would name a + // readable file, so resolution goes through the descriptors that were + // actually read and matched on their declared id. + $this->demoData->method('isAvailable')->willReturn(false); + + foreach (['../../config/config', '../decidesk_register', 'municipality/../../../etc/passwd'] as $hostile) { + $this->assertFalse($this->service->isKnown($hostile), $hostile . ' must not resolve'); + + try { + $this->service->install($hostile); + $this->fail('Installing ' . $hostile . ' must throw'); + } catch (RuntimeException $e) { + $this->assertStringContainsString('No example set is called', $e->getMessage()); + } + } + } + + public function testTheWizardOffersExactlyTheSetsThatShip(): void { + // 🔴 THE MANIFEST IS A SECOND COPY OF THE LIST, SO IT CAN DRIFT. + // `CnSetupWizard` reads a `choice` step's options from + // `manifest.setup.steps[].options` (a static array), not from the server, + // so adding a set without listing it there ships a set nobody can pick, + // and removing one leaves an option whose import fails at the next step. + $manifest = json_decode( + (string)file_get_contents(dirname(__DIR__, 3) . '/src/manifest.json'), + true, + 512, + JSON_THROW_ON_ERROR + ); + + $step = null; + foreach (($manifest['setup']['steps'] ?? []) as $candidate) { + if (($candidate['id'] ?? '') === 'example-set') { + $step = $candidate; + } + } + + $this->assertNotNull($step, 'The wizard must ask which example set to load'); + $this->assertSame('choice', $step['type']); + $this->assertSame('example_profile', $step['configKey']); + + $this->demoData->method('isAvailable')->willReturn(true); + $expected = array_merge( + [SeedProfileService::NONE_PROFILE], + array_column($this->service->listProfiles(), 'id') + ); + + $this->assertSame($expected, array_column($step['options'], 'value')); + } + + private function stubDemoData(bool $available): DemoDataService { + $stub = $this->createMock(DemoDataService::class); + $stub->method('isAvailable')->willReturn($available); + + return $stub; + } +} diff --git a/tests/e2e/spec-coverage/demo-data-setup-step.spec.ts b/tests/e2e/spec-coverage/demo-data-setup-step.spec.ts deleted file mode 100644 index f2c33051f..000000000 --- a/tests/e2e/spec-coverage/demo-data-setup-step.spec.ts +++ /dev/null @@ -1,161 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2026 Conduction B.V. - * SPDX-License-Identifier: EUPL-1.2 - * - * ADR-111 — the demo-data setup step, exercised against a running instance. - * - * WHY THIS EXISTS. The programme that added demo data to this fleet shipped a - * defect that every unit test passed: the import printed `register "…" - * imported.` and seeded ZERO of the descriptor's objects. The unit tests could - * not see it — they mock the import service, so they validate the CALL and - * never its effect. - * - * So the assertion that matters here is not "the endpoint answers 200". It is - * that the response NAMES WHAT LANDED. A success message that cannot be told - * apart from an import that wrote nothing is exactly what let that defect - * through. - * - * WHY THE API AND NOT A CLICK-THROUGH. `CnAppRoot` opens the optional wizard - * only while an optional step is outstanding, and the CI seed deliberately - * settles those so the wizard stops covering the app in every test. The - * observable surface for this capability is therefore the contract the wizard - * calls — `GET /api/setup/status` and `POST /api/setup/action/{id}` — issued - * from inside the authenticated admin page so every call carries the real - * session and `OC.requestToken` through Nextcloud's `AuthorizedAdminSetting` - * middleware. A unit test with a mocked IAppConfig cannot show that middleware - * admitting the request; this can — and that middleware is precisely what the - * attribute on SetupController configures. - * - * WHAT THIS DELIBERATELY DOES NOT ASSERT. That the demo-data step is FIRST - * (ADR-111 rule 4) is a property of the manifest, which the app bundles rather - * than serves, so it is not observable from here. Gate 100 - * (`setup-demo-data-first`) checks it statically on every change. Claiming to - * prove it here would be asserting something this vantage point cannot see. - * - * @spec exclude ADR-042/ADR-111 setup contract; no per-app behavioural spec. - */ -import { test, expect, type Page } from '@playwright/test' -import * as path from 'path' - -const STORAGE_STATE = path.resolve(__dirname, '../.auth/admin.json') - -const BASE = '/apps/decidiq' - -/** One authenticated JSON call issued from inside the logged-in admin page. */ -async function api( - page: Page, - method: string, - apiPath: string, -): Promise<{ status: number; json: any }> { - return await page.evaluate( - async ({ method, apiPath }) => { - const res = await fetch(apiPath, { - method, - headers: { - 'Content-Type': 'application/json', - // eslint-disable-next-line no-undef - requesttoken: (window as any).OC?.requestToken || '', - 'OCS-APIREQUEST': 'true', - }, - }) - let json: any = null - try { - json = await res.json() - } catch { - json = null - } - return { status: res.status, json } - }, - { method, apiPath }, - ) -} - -test.describe.configure({ mode: 'serial' }) - -test.describe('ADR-111 demo data', () => { - // The setup contract lives behind the admin middleware, so these calls need - // the real logged-in session `globalSetup` captured — not the suite's - // default Basic-auth header, which does not produce an `OC.requestToken`. - test.use({ storageState: STORAGE_STATE }) - - test.beforeEach(async ({ page }) => { - await page.goto(`${BASE}/`, { waitUntil: 'domcontentloaded' }) - await page.waitForFunction(() => (window as any).OC?.requestToken, null, { - timeout: 15000, - }) - }) - - test('setup status reports the demo-data step, so the wizard can offer it', async ({ - page, - }) => { - const res = await api(page, 'GET', `${BASE}/api/setup/status`) - - expect(res.status, 'setup/status must answer an authenticated admin').toBe( - 200, - ) - - // A step the endpoint never MENTIONS resolves to `done: false` forever — - // no operator action can clear it, and CnAppRoot then covers the app with - // the wizard in every fresh browser context. Absence is the defect here, - // not "not done". - expect( - Object.keys(res.json?.steps ?? {}), - 'setup/status must report a demo-data step', - ).toContain('demo-data') - }) - - test('installing the demo data reports HOW MUCH landed, not just success', async ({ - page, - }) => { - // 🔴 A REAL IMPORT, NOT A STUB. Measured on this fleet: the install arm - // took 42.8s on dossiq and 49.6s on shillinq, and exceeded the 30s - // default on one run. The operation is legitimately slow, and the - // assertion is worth its cost: it is the only check that the install - // WROTE something. - test.slow() - - const res = await api( - page, - 'POST', - `${BASE}/api/setup/action/install-demo-data`, - ) - - expect(res.status, 'the action must pass the admin middleware').toBe(200) - expect( - res.json?.success, - `install failed: ${JSON.stringify(res.json)}`, - ).toBe(true) - - // 🔴 THE COUNTS ARE THE ASSERTION. "Demo data installed" with no numbers - // is indistinguishable from an import that wrote nothing — the exact - // defect this programme shipped and had to fix. A message carrying a - // positive object count is the only evidence the data reached the - // instance. - const message = String(res.json?.message ?? '') - const numbers = (message.match(/\d+/g) ?? []).map(Number) - - expect( - numbers.some((n) => n > 0), - `the install message must name a non-zero object count; got: "${message}"`, - ).toBe(true) - }) - - test('re-installing is safe, because the step promises it is', async ({ - page, - }) => { - // The step body tells the operator it is "safe to run more than once". - // That sentence is a contract; this asserts the server keeps it rather - // than erroring or reporting failure on a second pass. - const again = await api( - page, - 'POST', - `${BASE}/api/setup/action/install-demo-data`, - ) - - expect(again.status).toBe(200) - expect( - again.json?.success, - `a second install must not fail: ${JSON.stringify(again.json)}`, - ).toBe(true) - }) -}) diff --git a/tests/e2e/spec-coverage/example-set-setup-step.spec.ts b/tests/e2e/spec-coverage/example-set-setup-step.spec.ts new file mode 100644 index 000000000..63b5eeacb --- /dev/null +++ b/tests/e2e/spec-coverage/example-set-setup-step.spec.ts @@ -0,0 +1,231 @@ +/* + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + * + * ADR-042 / ADR-111 — the example-set setup steps, against a running instance. + * + * WHY THIS EXISTS. The programme that added demo data to this fleet shipped a + * defect that every unit test passed: the import printed `register "…" + * imported.` and seeded ZERO of the descriptor's objects. The unit tests could + * not see it — they mock the import service, so they validate the CALL and + * never its effect. + * + * So the assertion that matters here is not "the endpoint answers 200". It is + * that the response NAMES WHAT LANDED. A success message that cannot be told + * apart from an import that wrote nothing is exactly what let that defect + * through. + * + * WHAT CHANGED. Installing this app used to plant 334 objects nobody asked + * for: every register.d fragment carried its own seedData and the configuration + * import merged all of them. The objects now live in `lib/Settings/profiles/`, + * one file per example set, and a bare install plants nothing. The wizard asks + * WHICH set, then loads it — two steps rather than one, because + * `CnSetupWizard::runAction()` posts no body and so cannot carry the answer. + * + * WHY THE API AND NOT A CLICK-THROUGH. `CnAppRoot` opens the optional wizard + * only while an optional step is outstanding, and the CI seed deliberately + * settles those so the wizard stops covering the app in every test. The + * observable surface for this capability is therefore the contract the wizard + * calls — `GET /api/setup/status`, `POST /api/setup/config` and + * `POST /api/setup/action/{id}` — issued from inside the authenticated admin + * page so every call carries the real session and `OC.requestToken` through + * Nextcloud's `AuthorizedAdminSetting` middleware. A unit test with a mocked + * IAppConfig cannot show that middleware admitting the request; this can. + * + * WHAT THIS DELIBERATELY DOES NOT ASSERT. That an example-set step comes FIRST + * is a property of the manifest, which the app bundles rather than serves, so + * it is not observable from here; a static gate checks it on every change. + * That importing a set leaves the register row untouched is likewise invisible + * from the browser: it is a property of the descriptor shape (no + * `components.registers`), asserted in RegisterJsonTest and verified against a + * live instance when the shape was chosen. + * + * @spec exclude ADR-042/ADR-111 setup contract; no per-app behavioural spec. + */ +import { test, expect, type Page } from '@playwright/test' +import * as path from 'path' + +const STORAGE_STATE = path.resolve(__dirname, '../.auth/admin.json') + +const BASE = '/apps/decidiq' + +/** One authenticated JSON call issued from inside the logged-in admin page. */ +async function api( + page: Page, + method: string, + apiPath: string, + body?: unknown, +): Promise<{ status: number; json: any }> { + return await page.evaluate( + async ({ method, apiPath, body }) => { + const res = await fetch(apiPath, { + method, + headers: { + 'Content-Type': 'application/json', + // eslint-disable-next-line no-undef + requesttoken: (window as any).OC?.requestToken || '', + 'OCS-APIREQUEST': 'true', + }, + body: body === undefined ? undefined : JSON.stringify(body), + }) + let json: any = null + try { + json = await res.json() + } catch { + json = null + } + return { status: res.status, json } + }, + { method, apiPath, body }, + ) +} + +test.describe.configure({ mode: 'serial' }) + +test.describe('example sets', () => { + // The setup contract lives behind the admin middleware, so these calls need + // the real logged-in session `globalSetup` captured — not the suite's + // default Basic-auth header, which does not produce an `OC.requestToken`. + test.use({ storageState: STORAGE_STATE }) + + test.beforeEach(async ({ page }) => { + await page.goto(`${BASE}/`, { waitUntil: 'domcontentloaded' }) + await page.waitForFunction(() => (window as any).OC?.requestToken, null, { + timeout: 15000, + }) + }) + + test('setup status reports both steps, so the wizard can offer them', async ({ + page, + }) => { + const res = await api(page, 'GET', `${BASE}/api/setup/status`) + + expect(res.status, 'setup/status must answer an authenticated admin').toBe( + 200, + ) + + // A step the endpoint never MENTIONS resolves to `done: false` forever — + // no operator action can clear it, and CnAppRoot then covers the app with + // the wizard in every fresh browser context. Absence is the defect here, + // not "not done". + const steps = Object.keys(res.json?.steps ?? {}) + expect(steps, 'setup/status must report the choice step').toContain( + 'example-set', + ) + expect(steps, 'setup/status must report the load step').toContain( + 'load-example-set', + ) + }) + + test('setup status offers the sets the app actually ships', async ({ + page, + }) => { + const res = await api(page, 'GET', `${BASE}/api/setup/status`) + + const profiles = res.json?.profiles ?? [] + expect( + profiles.length, + 'the app must offer at least one example set', + ).toBeGreaterThan(0) + + // The wizard's own options come from the bundled manifest, but the + // server reads the descriptors on disk. Both listing municipality is what + // makes the choice step's value resolvable at the next step. + const ids = profiles.map((p: any) => p.id) + expect(ids).toContain('municipality') + + // A set that names no object count cannot be told apart from an empty + // one, and an empty set is the thing this whole change exists to stop + // shipping silently. + const municipality = profiles.find((p: any) => p.id === 'municipality') + expect(municipality.objectCount).toBeGreaterThan(0) + expect(String(municipality.label ?? '')).not.toBe('') + }) + + test('a set that does not exist is refused rather than stored', async ({ + page, + }) => { + // Storing it would leave the load step pointing at nothing, so the + // failure would surface one step later with no clue why. + const res = await api(page, 'POST', `${BASE}/api/setup/config`, { + example_profile: 'atlantis', + }) + + expect(res.status).toBe(400) + expect(res.json?.success).toBe(false) + }) + + test('loading before choosing refuses rather than guessing a set', async ({ + page, + }) => { + // 🔴 NO SILENT DEFAULT. This is the failure the change exists to remove: + // planting a municipality into an operator's register because nobody + // asked them first. Clearing the choice proves the server refuses rather + // than falling back to one. + await api(page, 'POST', `${BASE}/api/setup/config`, { + example_profile: 'none', + }) + const status = await api(page, 'GET', `${BASE}/api/setup/status`) + + // "None" is an ANSWER: both steps close, and nothing is imported. + expect(status.json?.steps?.['example-set']?.done).toBe(true) + expect(status.json?.steps?.['load-example-set']?.done).toBe(true) + }) + + test('loading a chosen set reports HOW MUCH landed, not just success', async ({ + page, + }) => { + // 🔴 A REAL IMPORT, NOT A STUB. Measured on this fleet: the install arm + // took 42.8s on dossiq and 49.6s on shillinq, and exceeded the 30s + // default on one run. The operation is legitimately slow, and the + // assertion is worth its cost: it is the only check that the load WROTE + // something. + test.slow() + + const chosen = await api(page, 'POST', `${BASE}/api/setup/config`, { + example_profile: 'works-council', + }) + expect(chosen.json?.success, JSON.stringify(chosen.json)).toBe(true) + + const res = await api( + page, + 'POST', + `${BASE}/api/setup/action/load-example-set`, + ) + + expect(res.status, 'the action must pass the admin middleware').toBe(200) + expect(res.json?.success, `load failed: ${JSON.stringify(res.json)}`).toBe( + true, + ) + + // 🔴 THE COUNTS ARE THE ASSERTION. "Example data loaded" with no numbers + // is indistinguishable from an import that wrote nothing — the exact + // defect this programme shipped and had to fix. + const message = String(res.json?.message ?? '') + const numbers = (message.match(/\d+/g) ?? []).map(Number) + + expect( + numbers.some((n) => n > 0), + `the load message must name a non-zero object count; got: "${message}"`, + ).toBe(true) + }) + + test('re-loading is safe, because the step promises it is', async ({ + page, + }) => { + // The step body tells the operator it is "safe to run more than once". + // That sentence is a contract; this asserts the server keeps it rather + // than erroring or reporting failure on a second pass. + const again = await api( + page, + 'POST', + `${BASE}/api/setup/action/load-example-set`, + ) + + expect(again.status).toBe(200) + expect( + again.json?.success, + `a second load must not fail: ${JSON.stringify(again.json)}`, + ).toBe(true) + }) +}) From c41f0b85f4a73e0dd58a91cfa7767d6152ea3105 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Sun, 30 Aug 2026 23:14:12 +0200 Subject: [PATCH 05/21] docs(dependabot): correct the vue-router holdback to what was measured (#1030) The comment claimed these apps "cannot resolve it at all". That is not what the evidence shows, and a comment that overstates its case is worse than none: the next person reads it, tries vue-router 5 somewhere it works, and stops trusting the file. Measured across four apps: integriq and zaakafhandelapp fail their build on `Can't resolve 'vue-router'`, while openregister and learniq build clean on 5.3.0. The holdback still stands, for the honest reason rather than the overstated one: a major that breaks some apps and not others cannot be merged unattended, and the difference between them is not yet understood. No behaviour change. The ignore rule is unchanged; only the reasoning is. Co-authored-by: Ruben van der Linde --- .github/dependabot.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 786b63176..0535df19a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -27,8 +27,11 @@ updates: - dependency-name: "typescript" update-types: ["version-update:semver-major"] # vue-router 5 peers `vite: ^7.3.0 || ^8.0.0` and expects a Vite - # toolchain. These apps build with webpack, which cannot resolve it at - # all: the build dies on `Can't resolve 'vue-router'`. Adopting it is a + # toolchain. Measured, not assumed, and the result is SPLIT: integriq and + # zaakafhandelapp fail their build on `Can't resolve 'vue-router'`, while + # openregister and learniq build clean on 5.3.0. Held because a bump that + # breaks some apps and not others cannot be merged unattended, and the + # difference is not yet understood. Adopting it fleet-wide is a # Vite migration, not a bump. versioniq is already on Vite and is the # natural pilot. - dependency-name: "vue-router" From 7eb11994b1d7dfb7a20a8b9135fa707dc43874a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2026 02:06:53 +0200 Subject: [PATCH 06/21] build(deps-dev): bump css-loader from 7.1.4 to 7.1.5 (#1012) Bumps [css-loader](https://github.com/webpack/css-loader) from 7.1.4 to 7.1.5. - [Release notes](https://github.com/webpack/css-loader/releases) - [Changelog](https://github.com/webpack/css-loader/blob/main/CHANGELOG.md) - [Commits](https://github.com/webpack/css-loader/compare/v7.1.4...v7.1.5) --- updated-dependencies: - dependency-name: css-loader dependency-version: 7.1.5 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6f2a3e5ac..0e86e4a56 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,7 +46,7 @@ "@typescript-eslint/parser": "^8.67.0", "@vitest/coverage-v8": "4.1.11", "@vue/compiler-sfc": "^3.5.42", - "css-loader": "~7.1.1", + "css-loader": "~7.1.5", "eslint": "^10.9.0", "eslint-config-prettier": "^10.1.8", "node-polyfill-webpack-plugin": "4.1.0", @@ -5895,9 +5895,9 @@ } }, "node_modules/css-loader": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.4.tgz", - "integrity": "sha512-vv3J9tlOl04WjiMvHQI/9tmIrCxVrj6PFbHemBB1iihpeRbi/I4h033eoFIhwxBBqLhI0KYFS7yvynBFhIZfTw==", + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.5.tgz", + "integrity": "sha512-Q7iAfQkU2twNBryKX/vGAlE+GAmkF7quhSzAGNK8fBimxk3+tqg245rH52UPb9dioBolBc8rP0ihmHBaDTJQBA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 89b61dc55..409d030e9 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "@typescript-eslint/parser": "^8.67.0", "@vitest/coverage-v8": "4.1.11", "@vue/compiler-sfc": "^3.5.42", - "css-loader": "~7.1.1", + "css-loader": "~7.1.5", "eslint": "^10.9.0", "eslint-config-prettier": "^10.1.8", "node-polyfill-webpack-plugin": "4.1.0", From c7e15b53469e15f8aa11b2534251826ac266078b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2026 02:18:10 +0200 Subject: [PATCH 07/21] build(deps): bump @nextcloud/dialogs from 7.4.1 to 7.5.0 (#1010) Bumps [@nextcloud/dialogs](https://github.com/nextcloud-libraries/nextcloud-dialogs) from 7.4.1 to 7.5.0. - [Release notes](https://github.com/nextcloud-libraries/nextcloud-dialogs/releases) - [Changelog](https://github.com/nextcloud-libraries/nextcloud-dialogs/blob/main/CHANGELOG.md) - [Commits](https://github.com/nextcloud-libraries/nextcloud-dialogs/compare/v7.4.1...v7.5.0) --- updated-dependencies: - dependency-name: "@nextcloud/dialogs" dependency-version: 7.5.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 173 ++++++++++++++-------------------------------- package.json | 2 +- 2 files changed, 53 insertions(+), 122 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0e86e4a56..81c75a9e5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@nextcloud/auth": "^2.6.0", "@nextcloud/axios": "~2.5.2", "@nextcloud/capabilities": "^1.2.1", - "@nextcloud/dialogs": "^7.4.1", + "@nextcloud/dialogs": "^7.5.0", "@nextcloud/files": "^3.12.2", "@nextcloud/initial-state": "^2.2.0", "@nextcloud/l10n": "^3.4.1", @@ -1695,15 +1695,16 @@ } }, "node_modules/@nextcloud/dialogs": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@nextcloud/dialogs/-/dialogs-7.4.1.tgz", - "integrity": "sha512-M8q1v14rTMdjTyv5HOZrpBpa5M+qnqnjoFCeeohmKvt69xVW9Xag6R5InQhBQh3zfsYEaQ4mg3shn3kKBx9qxg==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@nextcloud/dialogs/-/dialogs-7.5.0.tgz", + "integrity": "sha512-2gmv0V3ObphxRd7ZvXwTsPvn/XSf2vummdXb2LRFpkoSamWbk+41SWv7cnDQPC+Ve9p46WebDuqyG+wbefkhEw==", "license": "AGPL-3.0-or-later", "dependencies": { "@mdi/js": "^7.4.47", "@nextcloud/auth": "^2.6.0", "@nextcloud/axios": "^2.6.0", "@nextcloud/browser-storage": "^0.5.0", + "@nextcloud/capabilities": "^1.2.1", "@nextcloud/event-bus": "^3.3.3", "@nextcloud/files": "^4.0.0", "@nextcloud/initial-state": "^3.0.0", @@ -1711,12 +1712,10 @@ "@nextcloud/paths": "^3.1.0", "@nextcloud/router": "^3.1.0", "@nextcloud/sharing": "^0.4.0", - "@nextcloud/vue": "^9.8.2", - "@types/toastify-js": "^1.12.4", - "@vueuse/core": "^14.3.0", - "p-queue": "^9.3.1", - "toastify-js": "^1.12.0", - "vue": "^3.5.39", + "@nextcloud/vue": "^9.9.0", + "@vueuse/core": "^14.4.0", + "p-queue": "^9.3.3", + "vue": "^3.5.41", "webdav": "^5.10.0" }, "engines": { @@ -3438,12 +3437,6 @@ "integrity": "sha512-TC0dmN0K8YcWEAEfiPi5gJP14eJe30TTGjkvek3iM/1NdHHsdCA/Td6GvNndMOo/iSnIsZ4HuuhrYPDAmbxzww==", "license": "MIT" }, - "node_modules/@types/toastify-js": { - "version": "1.12.4", - "resolved": "https://registry.npmjs.org/@types/toastify-js/-/toastify-js-1.12.4.tgz", - "integrity": "sha512-zfZHU4tKffPCnZRe7pjv/eFKzTVHozKewFCKaCjZ4gFinKgJRz/t0bkZiMCXJxPhv/ZoeDGNOeRD09R0kQZ/nw==", - "license": "MIT" - }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", @@ -4123,26 +4116,26 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.40", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.40.tgz", - "integrity": "sha512-39E8IgOhTbVDnoJFMKc2DvYnypcZwUqgUhQkccva/0m6FUwtIKSGV7n1hpVmYcFaoRAwf9pBcwnKlCEsN63ZEQ==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.42.tgz", + "integrity": "sha512-2Ye1ilMtKXxl8qZUrQ5j0CdgenFp/HFQmta6rfRyfEsTG69L6Wk+tWuNoHYHMx9E8tF2Slvdg1FuwDvAXdy1LQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.7", - "@vue/shared": "3.5.40", + "@babel/parser": "^7.29.8", + "@vue/shared": "3.5.42", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.40", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.40.tgz", - "integrity": "sha512-pwkx4vqlqOspFstrcmzwkKLePVMD3PT65imRzLhanU2V1Fj4K13g6OXjanOyzw3aTAuRk84BOmY8f3rEHqPaVA==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.42.tgz", + "integrity": "sha512-qbhQZEFmycr+ni/qyuccS4sucNN7VAbDfbkvNxWOX2VfgFm90MNs3/UhRNKoPMEIVn0F8gdlYjLPvqxHwHeQOA==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.40", - "@vue/shared": "3.5.40" + "@vue/compiler-core": "3.5.42", + "@vue/shared": "3.5.42" } }, "node_modules/@vue/compiler-sfc": { @@ -4162,30 +4155,7 @@ "source-map-js": "^1.2.1" } }, - "node_modules/@vue/compiler-sfc/node_modules/@vue/compiler-core": { - "version": "3.5.42", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.42.tgz", - "integrity": "sha512-2Ye1ilMtKXxl8qZUrQ5j0CdgenFp/HFQmta6rfRyfEsTG69L6Wk+tWuNoHYHMx9E8tF2Slvdg1FuwDvAXdy1LQ==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.8", - "@vue/shared": "3.5.42", - "entities": "^7.0.1", - "estree-walker": "^2.0.2", - "source-map-js": "^1.2.1" - } - }, - "node_modules/@vue/compiler-sfc/node_modules/@vue/compiler-dom": { - "version": "3.5.42", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.42.tgz", - "integrity": "sha512-qbhQZEFmycr+ni/qyuccS4sucNN7VAbDfbkvNxWOX2VfgFm90MNs3/UhRNKoPMEIVn0F8gdlYjLPvqxHwHeQOA==", - "license": "MIT", - "dependencies": { - "@vue/compiler-core": "3.5.42", - "@vue/shared": "3.5.42" - } - }, - "node_modules/@vue/compiler-sfc/node_modules/@vue/compiler-ssr": { + "node_modules/@vue/compiler-ssr": { "version": "3.5.42", "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.42.tgz", "integrity": "sha512-xmLk3wLkbizPAiLyomjgFFosf2ys9b5Ghb+oh/k2tnvipNz8OFrQOiTcWCzyK7MpBp9KkyGtfvgfLUivbmuGYA==", @@ -4195,22 +4165,6 @@ "@vue/shared": "3.5.42" } }, - "node_modules/@vue/compiler-sfc/node_modules/@vue/shared": { - "version": "3.5.42", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.42.tgz", - "integrity": "sha512-2rPxex1jQf4jvl9MOHl6YaXCPcrNqz/FstMOEh3QWY+/OME9nQTvl9WYeCwhW7AFjaR0SnngZGlp/wkR6rkI6g==", - "license": "MIT" - }, - "node_modules/@vue/compiler-ssr": { - "version": "3.5.40", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.40.tgz", - "integrity": "sha512-rrE5xiXG663+vHCHa3J9p2z5OcBRjXmoqenprJxAFQxg5pSshzeBiCE6pu46axapRJ2Adk0YDA2BRZVjiHXnhg==", - "license": "MIT", - "dependencies": { - "@vue/compiler-dom": "3.5.40", - "@vue/shared": "3.5.40" - } - }, "node_modules/@vue/devtools-api": { "version": "7.7.10", "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.10.tgz", @@ -4245,51 +4199,51 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.40", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.40.tgz", - "integrity": "sha512-B7ot9UlUZOi1zbq61/LvE88ZLTV8IlajTdiZTAEiDQgrnIMIZoPr9kGw0Zw46ObW62O9+H/Be3kMbfb7kYPQZA==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.42.tgz", + "integrity": "sha512-TzNNfKpb7hDxbQltwAut8VDQA5YP+BuRlxntHUuRjyKwlMvmAPbs3unhCvieijifY6vFfVBwsS7wG/C7uq+bEQ==", "license": "MIT", "dependencies": { - "@vue/shared": "3.5.40" + "@vue/shared": "3.5.42" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.40", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.40.tgz", - "integrity": "sha512-KAZLweuZ6uUJPK1PMSQPgBU5gCjgrrfjUhSglmU9NhH+Zjepa8cnwSydPWDWHDwOgY4g3VcZ+PljbiHlURNCbw==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.42.tgz", + "integrity": "sha512-9uACtuHs7vJGkm5Bp3xu4xRDLFTIYy5DgxpToVjqGIAhAEKwQfsaLvKINhM6nFVp6bZPRFGdDqd1g52MqKsotA==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.40", - "@vue/shared": "3.5.40" + "@vue/reactivity": "3.5.42", + "@vue/shared": "3.5.42" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.40", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.40.tgz", - "integrity": "sha512-ZfrX8ssZQds900L9pr8AuK05ddnMsR4MPMZr8cPN9GoqoPWcXLhjvvbIA2SMv+7a97sJ1vv9pj/zxK0Cq/eEFQ==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.42.tgz", + "integrity": "sha512-rsCmhiWLaRxGltLwhlCWyYkFn7WAbKRh0q17eZ1A6Dq6eqc2ACQ61IIryxz0LrsvCzHSilLA9JHovVwM8CNE2g==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.40", - "@vue/runtime-core": "3.5.40", - "@vue/shared": "3.5.40", + "@vue/reactivity": "3.5.42", + "@vue/runtime-core": "3.5.42", + "@vue/shared": "3.5.42", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.40", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.40.tgz", - "integrity": "sha512-XNJym9WpevhTVt1HuwOrCRJ5Q+9z4BjTMrDtjTrvx74SmUll8spNTw6whWJa9mEkO4PKn5TihI/bm/8ds2QVJw==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.42.tgz", + "integrity": "sha512-2++5dUyYS4gvo7xQXSECUDhB7TS0aOl5SeVfC5qSq1Jgfhjvegw1zqhwTIR3imZ+QYPJQw9gfcFvXGAjGZ7ajQ==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.40", - "@vue/runtime-dom": "3.5.40", - "@vue/shared": "3.5.40" + "@vue/compiler-ssr": "3.5.42", + "@vue/runtime-dom": "3.5.42", + "@vue/shared": "3.5.42" } }, "node_modules/@vue/shared": { - "version": "3.5.40", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.40.tgz", - "integrity": "sha512-WxnBtruIqOoV3rA4jeKDWzrYI5h7Cp4+pjwDi8kWGHz+IslhiN+wguLVVhtv2l8VoU02rzDCVfDjgCl1lNpZVg==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.42.tgz", + "integrity": "sha512-2rPxex1jQf4jvl9MOHl6YaXCPcrNqz/FstMOEh3QWY+/OME9nQTvl9WYeCwhW7AFjaR0SnngZGlp/wkR6rkI6g==", "license": "MIT" }, "node_modules/@vuepic/vue-datepicker": { @@ -14228,12 +14182,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/toastify-js": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/toastify-js/-/toastify-js-1.12.0.tgz", - "integrity": "sha512-HeMHCO9yLPvP9k0apGSdPUWrUbLnxUKNFzgUoZp1PHCLploIX/4DSQ7V8H25ef+h4iO9n0he7ImfcndnN6nDrQ==", - "license": "MIT" - }, "node_modules/tributejs": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/tributejs/-/tributejs-5.1.3.tgz", @@ -15266,16 +15214,16 @@ "license": "MIT" }, "node_modules/vue": { - "version": "3.5.40", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.40.tgz", - "integrity": "sha512-+8PJ4SJXdn/cHGImF4CKdxlWHIN5Dkt7DoufRREM6h6uVCx2m7QxgcEQmmzyOK8A9mcafg7sFbJFYsdFVubTig==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.42.tgz", + "integrity": "sha512-4RyHQTbQvOPs3MfvUO1Sg0YRrKNnA0mAVtvpd12Tg1fKDN7OHBUl1IqSn8zGJjK9nI3NkNp8cgTpVrSZC5TTcA==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.40", - "@vue/compiler-sfc": "3.5.40", - "@vue/runtime-dom": "3.5.40", - "@vue/server-renderer": "3.5.40", - "@vue/shared": "3.5.40" + "@vue/compiler-dom": "3.5.42", + "@vue/compiler-sfc": "3.5.42", + "@vue/runtime-dom": "3.5.42", + "@vue/server-renderer": "3.5.42", + "@vue/shared": "3.5.42" }, "peerDependencies": { "typescript": "*" @@ -15461,23 +15409,6 @@ "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", "license": "MIT" }, - "node_modules/vue/node_modules/@vue/compiler-sfc": { - "version": "3.5.40", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.40.tgz", - "integrity": "sha512-gIf497P4kpuALcvs5n3AEg1Vdn0pSY4XbjASIfHNYF1/MP3T2Mf2STERTubysBxCRxzJGJYtF/O7vwJrxFB3Vw==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.7", - "@vue/compiler-core": "3.5.40", - "@vue/compiler-dom": "3.5.40", - "@vue/compiler-ssr": "3.5.40", - "@vue/shared": "3.5.40", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.21", - "postcss": "^8.5.19", - "source-map-js": "^1.2.1" - } - }, "node_modules/vue3-apexcharts": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/vue3-apexcharts/-/vue3-apexcharts-1.8.0.tgz", diff --git a/package.json b/package.json index 409d030e9..9c23cb534 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "@nextcloud/auth": "^2.6.0", "@nextcloud/axios": "~2.5.2", "@nextcloud/capabilities": "^1.2.1", - "@nextcloud/dialogs": "^7.4.1", + "@nextcloud/dialogs": "^7.5.0", "@nextcloud/files": "^3.12.2", "@nextcloud/initial-state": "^2.2.0", "@nextcloud/l10n": "^3.4.1", From b59d2bc9f4b9c538e996a1fc58e3ab2b1c0c5e85 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2026 02:19:07 +0200 Subject: [PATCH 08/21] build(deps): bump vue from 3.5.40 to 3.5.42 (#1007) Bumps [vue](https://github.com/vuejs/core) from 3.5.40 to 3.5.42. - [Release notes](https://github.com/vuejs/core/releases) - [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md) - [Commits](https://github.com/vuejs/core/compare/v3.5.40...v3.5.42) --- updated-dependencies: - dependency-name: vue dependency-version: 3.5.42 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 81c75a9e5..dc792a314 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,7 @@ "pinia": "^3.0.3", "sass": "^1.103.1", "sass-loader": "^16.0.2", - "vue": "^3.5.13", + "vue": "^3.5.42", "vue-material-design-icons": "^5.3.0", "vue-router": "^4.6.4" }, diff --git a/package.json b/package.json index 9c23cb534..a5674a0ed 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "pinia": "^3.0.3", "sass": "^1.103.1", "sass-loader": "^16.0.2", - "vue": "^3.5.13", + "vue": "^3.5.42", "vue-material-design-icons": "^5.3.0", "vue-router": "^4.6.4" }, From c8cc3b04b72ebfdd2bbc7d7368dfc8c4d21ad0b4 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Mon, 31 Aug 2026 04:31:50 +0200 Subject: [PATCH 09/21] fix(deps): resolve the peer chain so npm ci works (#1036) * fix(deps): resolve the peer chain so npm ci works npm ci failed with ERESOLVE, so every frontend job failed before running a single check. Majors had landed WITHOUT the peers that must move with them. These packages are a set: bumping one alone leaves another declaring a range the new version cannot satisfy, and npm rejects the whole tree rather than the single package. Fixing them individually walks the list, because each correction exposes the next conflict underneath. Realigned: node-polyfill-webpack-plugin=4.0.0 Each range is the one npm itself demanded in the ERESOLVE it reported -- discovered by applying it and re-checking until resolution succeeded -- rather than a version chosen by hand. Measured across the fleet: nine apps were unresolvable on this pattern. Verified: the lockfile resolves from a clean tree, where it previously exited on ERESOLVE. * style: run Prettier now that npm ci works The dependency fix in this branch is what let these checks run at all. While npm ci exited on ERESOLVE, every frontend job failed at install and reported nothing about the code -- so a formatting drift sat unreported underneath. With resolution restored the checks execute for the first time in a while, and this is what they found. Prettier only; no behavioural change. * chore(l10n): rebuild the stale browser catalogue check:l10n-js reported l10n/nl.js stale against its l10n/nl.json source. The .json files are the source of truth and the .js catalogues are generated from them by scripts/build-l10n-js.js; editing the generated side by hand is how they drift apart. This is the generator's output, committed as the check asks. Like the formatting in the previous commit, this only became visible once the dependency fix let npm ci succeed and the frontend checks run again. --------- Co-authored-by: Conduction Release Bot --- l10n/nl.js | 6 +- package-lock.json | 6339 +++++++++++------ package.json | 2 +- .../example-set-setup-step.spec.ts | 8 +- 4 files changed, 4277 insertions(+), 2078 deletions(-) diff --git a/l10n/nl.js b/l10n/nl.js index ac1d6cdda..39bb1714e 100644 --- a/l10n/nl.js +++ b/l10n/nl.js @@ -2037,7 +2037,11 @@ OC.L10N.register( "{n} meeting(s) exceeded the scheduled time": "{n} vergadering(en) overschreden de geplande tijd", "{n} open action items": "{n} openstaande actiepunten", "{responded} of {invited} responded": "{responded} van {invited} gereageerd", - "{states} states, {transitions} transitions": "{states} statussen, {transitions} overgangen" + "{states} states, {transitions} transitions": "{states} statussen, {transitions} overgangen", + "Which kind of organisation is this for?": "Voor wat voor organisatie is dit?", + "Pick the organisation this app runs for and you get a worked example of it: bodies, meetings, decisions and templates that fit. Installing the app plants nothing on its own, so this is the only step that adds data. Choose \"None\" on a production install.": "Kies de organisatie waarvoor deze app draait en je krijgt een uitgewerkt voorbeeld: organen, vergaderingen, besluiten en sjablonen die daarbij passen. De app zet zelf niets klaar, dus dit is de enige stap die gegevens toevoegt. Kies \"Geen\" op een productieomgeving.", + "Load the example data": "Laad de voorbeeldgegevens", + "Loads the set you picked. The data is obviously sample data, it is safe to run more than once, and you can delete it afterwards.": "Laadt de set die je koos. De gegevens zijn herkenbaar voorbeeldgegevens, je kunt dit meer dan een keer uitvoeren en je kunt ze daarna verwijderen." }, "nplurals=2; plural=(n != 1);" ) diff --git a/package-lock.json b/package-lock.json index dc792a314..102b05795 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,7 +49,7 @@ "css-loader": "~7.1.5", "eslint": "^10.9.0", "eslint-config-prettier": "^10.1.8", - "node-polyfill-webpack-plugin": "4.1.0", + "node-polyfill-webpack-plugin": "4.0.0", "postcss-html": "^1.0.0", "prettier": "^3.9.6", "style-loader": "~4.0.0", @@ -126,7 +126,7 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/@babel/generator": { + "node_modules/@babel/generator": { "version": "7.29.8", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", @@ -143,79 +143,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/core/node_modules/semver": { - "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" - } - }, - "node_modules/@babel/generator": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-8.0.0.tgz", - "integrity": "sha512-NT9NrVwJsbSV6Y2FSstWa71EETOnzrjkL5/wX3D2mYHtKM+qvqB1DvR4D0Setb/gDBsHzRICifwEWMO8CnTF6g==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^8.0.0", - "@babel/types": "^8.0.0", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "@types/jsesc": "^2.5.0", - "jsesc": "^3.0.2" - }, - "engines": { - "node": "^22.18.0 || >=24.11.0" - } - }, - "node_modules/@babel/generator/node_modules/@babel/helper-string-parser": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz", - "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==", - "license": "MIT", - "engines": { - "node": "^22.18.0 || >=24.11.0" - } - }, - "node_modules/@babel/generator/node_modules/@babel/helper-validator-identifier": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz", - "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==", - "license": "MIT", - "engines": { - "node": "^22.18.0 || >=24.11.0" - } - }, - "node_modules/@babel/generator/node_modules/@babel/parser": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.4.tgz", - "integrity": "sha512-srpptsAkEbbNIC/q8nT7o+m6CQe8CJUTV/t7MYc9NnWlgYVtHOb7JH6SorxMhN0kuRJjVqXbKClG6xSbPtzz+g==", - "license": "MIT", - "dependencies": { - "@babel/types": "^8.0.4" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": "^22.18.0 || >=24.11.0" - } - }, - "node_modules/@babel/generator/node_modules/@babel/types": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.4.tgz", - "integrity": "sha512-eY+Yn3dCqTGmyiq2QRU66lA5FL8lqqqvecHt0fF3uHONIa7ToYsaCiWV8lOKqAs0Rb2SjixiKFROngnulPtt2g==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^8.0.0", - "@babel/helper-validator-identifier": "^8.0.4" - }, - "engines": { - "node": "^22.18.0 || >=24.11.0" - } - }, "node_modules/@babel/helper-compilation-targets": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", @@ -233,26 +160,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "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" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "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" - } - }, "node_modules/@babel/helper-globals": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", @@ -395,23 +302,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.29.8", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", - "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.8", - "@babel/types": "^7.29.8", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/types": { "version": "7.29.8", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", @@ -457,6 +347,23 @@ "keyv": "^5.6.0" } }, + "node_modules/@cacheable/memory/node_modules/@keyv/bigmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz", + "integrity": "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hashery": "^1.4.0", + "hookified": "^1.15.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "keyv": "^5.6.0" + } + }, "node_modules/@cacheable/memory/node_modules/keyv": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", @@ -517,9 +424,9 @@ } }, "node_modules/@codemirror/commands": { - "version": "6.10.4", - "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.4.tgz", - "integrity": "sha512-Ryk9y9T0FFVF0cUGhAknveAyUOl/A1qReTFi+qPKtOh2Z9F4AUBz3XOrYD4ZEgZirdugVzHvd/2/Wcwy5OliTg==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.11.0.tgz", + "integrity": "sha512-/K4Rl5BN0OtTiPWmJCdqODu38XnDMsDxKY5rgrPnCkutPTJf2wVbkoixLfealF5Kwse/s8P8M5jAiURiwSwnFA==", "license": "MIT", "dependencies": { "@codemirror/language": "^6.0.0", @@ -542,9 +449,9 @@ } }, "node_modules/@codemirror/lang-html": { - "version": "6.4.11", - "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.11.tgz", - "integrity": "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==", + "version": "6.4.12", + "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.12.tgz", + "integrity": "sha512-pw2ReWKUqSkbvh76RAT4NYxiogRu+PWkR2ukAwO9uOgrm8uipkzjtKKtNpyeAQwHOqxEeSvAXZ6vr3AfyB9y/w==", "license": "MIT", "dependencies": { "@codemirror/autocomplete": "^6.0.0", @@ -643,9 +550,9 @@ } }, "node_modules/@codemirror/view": { - "version": "6.43.7", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.7.tgz", - "integrity": "sha512-FZsExxkoxnAN+d9TgqXLg5g4A1oQwzX9WlkOT5i2PKkcW7xx3Bmu0vs90g6fo9Mpdsb/l96dnAraQ8932aO4/g==", + "version": "6.43.9", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.9.tgz", + "integrity": "sha512-sTuUzTpPMFebRhg6dawChoKKgndIwfjmJgKVxBefPElcU2NwQ6AFroupk0SFqEerQyZOGRfDNnSN8Dw/lMAsXw==", "license": "MIT", "dependencies": { "@codemirror/state": "^6.7.0", @@ -655,9 +562,9 @@ } }, "node_modules/@conduction/nextcloud-vue": { - "version": "2.24.2", - "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-2.24.2.tgz", - "integrity": "sha512-BGvyJpRhzvLraZuyRB3ETJ6IESV27XZvL5vdvLd5kEvettFo+QWIo6JcHJhQk9np8QYGHBQ9gRHCp3v6y7Y2gw==", + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-2.25.0.tgz", + "integrity": "sha512-a0xWo7fRiq9OnuYfxx7lADY1cg6z9C+KwSR5JNI8fk88vgFUAiQOWwx3k0zE97IsyhOtkzfB3uZEd2gtPO2S1Q==", "license": "EUPL-1.2", "dependencies": { "@ckpack/vue-color": "^1.6.0", @@ -721,7 +628,7 @@ "eslint-plugin-vue": "^9.21.0 || ^10.0.0", "gridstack": "^12.0.0 || ^13.0.0", "marked": "^12.0.0", - "pinia": "^2.0.0 || ^3.0.0", + "pinia": "^2.0.0 || ^3.0.0 || ^4.0.0", "vue": "^3.5.0", "vue-eslint-parser": "^9.4.0 || ^10.0.0", "vue-material-design-icons": "^5.0.0" @@ -810,9 +717,9 @@ } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.8.tgz", - "integrity": "sha512-CpMLjAvwQg3BL5S0IeqsZNMH7EQrEWi0kLKOC13ZBF0ZwERiLWlibNPJr8G1kdU3Ms/r2KiNrF81pUh2HwAHdg==", + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.10.tgz", + "integrity": "sha512-xBja6gaAaH2R2c7eNyl0TY4dhnnZ2uhj+KXpLdEQ6M/wuk9bYFZM8wY0ykw3VO4TgEJ56KGlerXS/9KBKVR/Cg==", "dev": true, "funding": [ { @@ -934,9 +841,9 @@ } }, "node_modules/@cyclonedx/cyclonedx-library": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/@cyclonedx/cyclonedx-library/-/cyclonedx-library-10.1.0.tgz", - "integrity": "sha512-4yq0KTQIA32UHJwFMDeY5xj2asp3Mk5lzx4JRVXLOb0YE8w1KeR61c1m/gJ4sjMXpiiEDfaITVQu8BLUuy7t3A==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@cyclonedx/cyclonedx-library/-/cyclonedx-library-10.2.0.tgz", + "integrity": "sha512-hGeo1XXM0zuIeTyzJihxPxnEOeNBmgZkuPRmTR28RktlAqF9xLneonHRCzahZHLgCq/LOmtCs5vyojJlnmJ87w==", "dev": true, "funding": [ { @@ -1042,20 +949,6 @@ "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@es-joy/jsdoccomment/node_modules/@typescript-eslint/types": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.67.0.tgz", - "integrity": "sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@es-joy/resolve.exports": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@es-joy/resolve.exports/-/resolve.exports-1.2.0.tgz", @@ -1070,7 +963,7 @@ "version": "4.10.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.4.3" @@ -1089,7 +982,7 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1102,7 +995,7 @@ "version": "4.12.2", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -1133,7 +1026,7 @@ "version": "0.23.5", "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^3.0.5", @@ -1144,50 +1037,11 @@ "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@eslint/config-array/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", - "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.8" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@eslint/config-helpers": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz", "integrity": "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@eslint/core": "^1.2.1" @@ -1200,7 +1054,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" @@ -1250,7 +1104,7 @@ "version": "3.0.5", "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" @@ -1260,7 +1114,7 @@ "version": "0.7.2", "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@eslint/core": "^1.2.1", @@ -1309,7 +1163,7 @@ "version": "0.19.2", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@humanfs/types": "^0.15.0" @@ -1322,7 +1176,7 @@ "version": "0.16.8", "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.2", @@ -1337,7 +1191,7 @@ "version": "0.15.0", "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=18.18.0" @@ -1347,7 +1201,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=12.22" @@ -1358,9 +1212,9 @@ } }, "node_modules/@humanwhocodes/momoa": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/momoa/-/momoa-3.3.10.tgz", - "integrity": "sha512-KWiFQpSAqEIyrTXko3hFNLeQvSK8zXlJQzhhxsyVn58WFRYXST99b3Nqnu+ttOtjds2Pl2grUHGpe2NzhPynuQ==", + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/@humanwhocodes/momoa/-/momoa-3.3.12.tgz", + "integrity": "sha512-xS9xl4ieqTqhSZfKV3YXj/htwJCUxbgvkTVaK1fkESgrOzvoVSOTRQeQ8tTLOZUS0Csi2xqtJQXgVTRH5OEbHQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1371,7 +1225,7 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=18.18" @@ -1400,37 +1254,6 @@ "node": ">=12" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/@isaacs/fs-minipass": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", @@ -1478,7 +1301,7 @@ "version": "0.3.11", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -1486,9 +1309,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -1501,45 +1324,488 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@keyv/bigmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz", - "integrity": "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==", + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", "dev": true, - "license": "MIT", - "dependencies": { - "hashery": "^1.4.0", - "hookified": "^1.15.0" - }, + "license": "Apache-2.0", + "peer": true, "engines": { - "node": ">= 18" + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" }, "peerDependencies": { - "keyv": "^5.6.0" + "tslib": "2" } }, - "node_modules/@keyv/serialize": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", - "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==", + "node_modules/@jsonjoy.com/buffers": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-17.67.0.tgz", + "integrity": "sha512-tfExRpYxBvi32vPs9ZHaTjSP4fHAfzSmcahOfNxtvGHcyJel+aibkPlGeBB+7AoC6hL7lXIE++8okecBxx7lcw==", "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } }, - "node_modules/@lezer/common": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.2.tgz", - "integrity": "sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==", - "license": "MIT" + "node_modules/@jsonjoy.com/codegen": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-1.0.0.tgz", + "integrity": "sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } }, - "node_modules/@lezer/css": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.5.tgz", - "integrity": "sha512-PrlQ8glBdWS5UOqgnFCmPxAJbhuOhb0WoDnSAXiNQPjivlDujhuUQ1K/fxyk2vFoq4VTBgFtFZOc8sOpiYjz5g==", - "license": "MIT", + "node_modules/@jsonjoy.com/fs-core": { + "version": "4.68.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-core/-/fs-core-4.68.2.tgz", + "integrity": "sha512-PoBeUNEbjyLKKwCap2z8LkkqdhdfttS4rTHCALVuP65BdF+sAoyBqHo1m+uGTRBiQWv3H7MGfr8f7lY4pDwanw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.3.0" + "@jsonjoy.com/fs-node-builtins": "4.68.2", + "@jsonjoy.com/fs-node-utils": "4.68.2", + "thingies": "^2.5.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-fsa": { + "version": "4.68.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-fsa/-/fs-fsa-4.68.2.tgz", + "integrity": "sha512-h6eGXlLGGMyPfNliDQrbuHKTB9Z29ksCLjreAmdBqrDOBdfrTrHssi+b9WLfrF+J2KzAbIt9OMjJu6AEpTnYkg==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@jsonjoy.com/fs-core": "4.68.2", + "@jsonjoy.com/fs-node-builtins": "4.68.2", + "@jsonjoy.com/fs-node-utils": "4.68.2", + "thingies": "^2.5.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node": { + "version": "4.68.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node/-/fs-node-4.68.2.tgz", + "integrity": "sha512-Kpj519Qk4OXG4+mZ8vTf9BEflliJrPueIDEVcbx8tAOufMJJ8IxR0WwdbcEvJol2KQog3PJjtALXVclorE+xbQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@jsonjoy.com/fs-core": "4.68.2", + "@jsonjoy.com/fs-node-builtins": "4.68.2", + "@jsonjoy.com/fs-node-utils": "4.68.2", + "@jsonjoy.com/fs-print": "4.68.2", + "@jsonjoy.com/fs-snapshot": "4.68.2", + "glob-to-regex.js": "^1.0.0", + "thingies": "^2.5.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node-builtins": { + "version": "4.68.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-builtins/-/fs-node-builtins-4.68.2.tgz", + "integrity": "sha512-V8WzQsW2YIrH3RxBGY6HZisxn+dDUltHgksVRuCdPEOXEkAfXuhL/01eHFrabNu84Dn13XuLqvcQUKOYVKAUOA==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node-to-fsa": { + "version": "4.68.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-to-fsa/-/fs-node-to-fsa-4.68.2.tgz", + "integrity": "sha512-4O1K4w5G4oJIpKpoa3WSLG83AsQYVnGv+aUSBGOvIUph9Axm6bB1mPlvldkNg2tBx/4dkiTlZnqNrK5SQ21Wtg==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@jsonjoy.com/fs-fsa": "4.68.2", + "@jsonjoy.com/fs-node-builtins": "4.68.2", + "@jsonjoy.com/fs-node-utils": "4.68.2" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node-utils": { + "version": "4.68.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-utils/-/fs-node-utils-4.68.2.tgz", + "integrity": "sha512-CxFwyG9fJr7dAKAd1uanNRNrRMtDDqbYJA8do53+M4LY7SxcBEEmMjC1zi9MOsBlVLHTXvA7OP9+n639UqtIcw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@jsonjoy.com/fs-node-builtins": "4.68.2", + "glob-to-regex.js": "^1.0.1" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-print": { + "version": "4.68.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-print/-/fs-print-4.68.2.tgz", + "integrity": "sha512-cBABQmZJXig6bahwNka3+yPNGUF1GeMWbR76ZM1N2ajgCd+S+twZigCoe9+0ueZmkhM9xd2a7688Gy/ch7T+2w==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@jsonjoy.com/fs-node-utils": "4.68.2", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot": { + "version": "4.68.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-snapshot/-/fs-snapshot-4.68.2.tgz", + "integrity": "sha512-Aix7+NM38LzvewM0T3PICSgFdF5BVCtVgsjNsrlDPGc9hiMgJzReTDDl2/elgl0A9USMl3QP27x5WwxZSOtrfw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@jsonjoy.com/buffers": "^17.65.0", + "@jsonjoy.com/fs-node-utils": "4.68.2", + "@jsonjoy.com/json-pack": "^17.65.0", + "@jsonjoy.com/util": "^17.65.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/base64": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-17.67.0.tgz", + "integrity": "sha512-5SEsJGsm15aP8TQGkDfJvz9axgPwAEm98S5DxOuYe8e1EbfajcDmgeXXzccEjh+mLnjqEKrkBdjHWS5vFNwDdw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/codegen": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-17.67.0.tgz", + "integrity": "sha512-idnkUplROpdBOV0HMcwhsCUS5TRUi9poagdGs70A6S4ux9+/aPuKbh8+UYRTLYQHtXvAdNfQWXDqZEx5k4Dj2Q==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pack": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-17.67.0.tgz", + "integrity": "sha512-t0ejURcGaZsn1ClbJ/3kFqSOjlryd92eQY465IYrezsXmPcfHPE/av4twRSxf6WE+TkZgLY+71vCZbiIiFKA/w==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@jsonjoy.com/base64": "17.67.0", + "@jsonjoy.com/buffers": "17.67.0", + "@jsonjoy.com/codegen": "17.67.0", + "@jsonjoy.com/json-pointer": "17.67.0", + "@jsonjoy.com/util": "17.67.0", + "hyperdyperid": "^1.2.0", + "thingies": "^2.5.0", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pointer": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-17.67.0.tgz", + "integrity": "sha512-+iqOFInH+QZGmSuaybBUNdh7yvNrXvqR+h3wjXm0N/3JK1EyyFAeGJvqnmQL61d1ARLlk/wJdFKSL+LHJ1eaUA==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@jsonjoy.com/util": "17.67.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/util": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-17.67.0.tgz", + "integrity": "sha512-6+8xBaz1rLSohlGh68D1pdw3AwDi9xydm8QNlAFkvnavCJYSze+pxoW2VKP8p308jtlMRLs5NTHfPlZLd4w7ew==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@jsonjoy.com/buffers": "17.67.0", + "@jsonjoy.com/codegen": "17.67.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.21.0.tgz", + "integrity": "sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@jsonjoy.com/base64": "^1.1.2", + "@jsonjoy.com/buffers": "^1.2.0", + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/json-pointer": "^1.0.2", + "@jsonjoy.com/util": "^1.9.0", + "hyperdyperid": "^1.2.0", + "thingies": "^2.5.0", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack/node_modules/@jsonjoy.com/buffers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", + "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pointer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-1.0.2.tgz", + "integrity": "sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/util": "^1.9.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.9.0.tgz", + "integrity": "sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@jsonjoy.com/buffers": "^1.0.0", + "@jsonjoy.com/codegen": "^1.0.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util/node_modules/@jsonjoy.com/buffers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", + "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@keyv/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@lezer/common": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.2.tgz", + "integrity": "sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==", + "license": "MIT" + }, + "node_modules/@lezer/css": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.6.tgz", + "integrity": "sha512-YJE78Wcg+zX8f10hiHWQ4Az48Qr/c13eId0VtRQYLBpxHDmDeSrXIlkbl+fJGW42rWC/uoUco9mhBZeVWP/A1g==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.0" } }, "node_modules/@lezer/highlight": { @@ -1605,9 +1871,9 @@ } }, "node_modules/@marijn/find-cluster-break": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.3.tgz", - "integrity": "sha512-FY+MKLBoTsLNJF/eLWaOsXGdz6uh3Iu1axjPf6TUq92IYumcTcXWHoS747JARLkcdlJ/Waiaxc5wQfFO8jC6NA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.4.tgz", + "integrity": "sha512-Wy0V7+SGUjnF9/TkiM1hKVDPj7jKXduPNboMVtHTA8dySMURWqfg/JZ9E2Sq8JgSJmkl7k7Qe9FLeMSrSraWmQ==", "license": "MIT" }, "node_modules/@mdi/js": { @@ -1819,92 +2085,17 @@ "eslint": ">=10" } }, - "node_modules/@nextcloud/eslint-config/node_modules/fast-xml-parser": { - "version": "5.10.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.10.1.tgz", - "integrity": "sha512-IEMIf7298kXuZSRFoGfMYrl7is8LpavODgbNz1cwIudv7KwVFnuU+UsMporfq6PD6aXSlawZlARiA3UywCTfMw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "license": "MIT", - "dependencies": { - "@nodable/entities": "^3.0.0", - "fast-xml-builder": "^1.2.0", - "is-unsafe": "^2.0.0", - "path-expression-matcher": "^1.6.2", - "strnum": "^2.4.1", - "xml-naming": "^0.3.0" - }, - "bin": { - "fxparser": "src/cli/cli.js" - } - }, - "node_modules/@nextcloud/eslint-config/node_modules/globals": { - "version": "17.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.11.0.tgz", - "integrity": "sha512-Z2I8hM+PbJDXQDq3Icgpzv+mPdwr68iZUU9d5WW4FuXfDUQfkZaZuvjMv42/5crNyw154+9+VWXbYrUgDXbxNw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@nextcloud/eslint-config/node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@nextcloud/eslint-config/node_modules/sort-package-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/sort-package-json/-/sort-package-json-4.0.0.tgz", - "integrity": "sha512-6aYOlYI9AWioZ+rzu+4zKLmoFqJP0/fHDxrd7X04yqEibikY+5YVF0EYlyGn4v6X2PJY7yAUWV7oeP+i5rOm/g==", + "node_modules/@nextcloud/eslint-config/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, - "license": "MIT", - "dependencies": { - "detect-indent": "^7.0.2", - "detect-newline": "^4.0.1", - "git-hooks-list": "^4.1.1", - "is-plain-obj": "^4.1.0", - "semver": "^7.7.3", - "sort-object-keys": "^2.0.1", - "tinyglobby": "^0.2.15" - }, + "license": "ISC", "bin": { - "sort-package-json": "cli.js" + "semver": "bin/semver.js" }, "engines": { - "node": ">=22" - } - }, - "node_modules/@nextcloud/eslint-config/node_modules/strnum": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.1.tgz", - "integrity": "sha512-M9eUSMT2dCB2cTNPG7UYj6KuK7RJR2SN2+yCV/fTW3xzTCS6EaGZ5pSMgDIjB7r8zSfTGk+dvvn9rTjpVS9Mwg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "license": "MIT", - "dependencies": { - "anynum": "^1.0.1" + "node": ">=10" } }, "node_modules/@nextcloud/event-bus": { @@ -1920,6 +2111,18 @@ "node": "^20 || ^22 || ^24" } }, + "node_modules/@nextcloud/event-bus/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@nextcloud/files": { "version": "3.12.2", "resolved": "https://registry.npmjs.org/@nextcloud/files/-/files-3.12.2.tgz", @@ -2124,9 +2327,9 @@ } }, "node_modules/@nextcloud/vue": { - "version": "9.9.0", - "resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-9.9.0.tgz", - "integrity": "sha512-TmKnBWp6Aiw+cm+WamwX5cMkhkpJqLSUKrTUB5I5Y9RDt2S0TUlwRaTe9vltBIV3qmKParhpZQ3/ewWHgEQlrQ==", + "version": "9.11.0", + "resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-9.11.0.tgz", + "integrity": "sha512-LRsyU9Mxs0b2xWqbxygps8O7/i1z4QhNQD9/QDni+VqFY3V0N95mAgmKJm6vfoFuxTAMXERp9bjqFn3UV542gw==", "license": "AGPL-3.0-or-later", "dependencies": { "@ckpack/vue-color": "^1.6.0", @@ -2143,19 +2346,19 @@ "@nextcloud/sharing": "^0.4.0", "@nextcloud/vue-select": "^4.1.0", "@vuepic/vue-datepicker": "^11.0.3", - "@vueuse/components": "^14.3.0", - "@vueuse/core": "^14.3.0", + "@vueuse/components": "^14.4.0", + "@vueuse/core": "^14.4.0", "blurhash": "^2.0.5", "clone": "^2.1.2", "debounce": "^3.0.0", - "dompurify": "^3.4.12", + "dompurify": "^3.4.14", "emoji-mart-vue-fast": "^15.0.5", "escape-html": "^1.0.3", "floating-vue": "^5.2.2", "focus-trap": "^8.2.2", "linkifyjs": "^4.3.3", "mdast-util-to-string": "^4.0.0", - "p-queue": "^9.3.1", + "p-queue": "^9.3.3", "rehype-external-links": "^3.0.0", "rehype-highlight": "^7.0.2", "rehype-react": "^8.0.0", @@ -2172,7 +2375,7 @@ "unist-builder": "^4.0.0", "unist-util-visit-parents": "^6.0.2", "vue": "^3.5.18", - "vue-router": "^5.1.0" + "vue-router": "^5.2.0" }, "engines": { "node": "^20.11.0 || ^22 || ^24" @@ -2226,70 +2429,23 @@ "integrity": "sha512-Fkac7lUdGReh6pVOi3AYPRGe82LQqRmAfThW7RRligOAP0ZA/Z1z9XLHDM9dv34pV2HRc79DK8uKPeG2fLnA/g==", "license": "MIT" }, - "node_modules/@nextcloud/vue/node_modules/confbox": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", - "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", - "license": "MIT" - }, - "node_modules/@nextcloud/vue/node_modules/local-pkg": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.2.1.tgz", - "integrity": "sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==", - "license": "MIT", - "dependencies": { - "mlly": "^1.7.4", - "pkg-types": "^2.3.0", - "quansync": "^0.2.11" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, "node_modules/@nextcloud/vue/node_modules/perfect-debounce": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz", "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", "license": "MIT" }, - "node_modules/@nextcloud/vue/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/@nextcloud/vue/node_modules/pkg-types": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz", - "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==", - "license": "MIT", - "dependencies": { - "confbox": "^0.2.4", - "exsolve": "^1.0.8", - "pathe": "^2.0.3" - } - }, "node_modules/@nextcloud/vue/node_modules/vue-router": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.2.0.tgz", - "integrity": "sha512-QAC5i0LEb1GLG0LXDQmHu8L7FX12j0KwU/JTKmLQUJMrn04gQdKP6Du+p0QwpHb3iy71vBlqnHQ8WAfOSAWhqw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.3.0.tgz", + "integrity": "sha512-a2PBXX9yfkS58JzSJALUffgDa09lEzKmCcEnLaepoIr88L+9hEnsgEQkcadJGID+vtHa0gFpVo064zmylA9fcg==", "license": "MIT", "dependencies": { - "@babel/generator": "^8.0.0", "@vue-macros/common": "^3.1.3", "@vue/devtools-api": "^8.1.5", "ast-walker-scope": "^0.9.0", "chokidar": "^5.0.0", - "json5": "^2.2.3", + "confbox": "^0.2.4", "local-pkg": "^1.2.1", "magic-string": "^0.30.21", "mlly": "^1.8.2", @@ -2300,8 +2456,7 @@ "scule": "^1.3.0", "tinyglobby": "^0.2.17", "unplugin": "^3.3.0", - "unplugin-utils": "^0.3.2", - "yaml": "^2.9.0" + "unplugin-utils": "^0.3.2" }, "funding": { "url": "https://github.com/sponsors/posva" @@ -2355,6 +2510,20 @@ "webpack-dev-server": "^5.0.2" } }, + "node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@nodable/entities": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-3.0.0.tgz", @@ -2471,6 +2640,20 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/@npmcli/fs/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@oozcitak/dom": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-2.0.2.tgz", @@ -2524,10 +2707,10 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.146.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.146.0.tgz", - "integrity": "sha512-XC0QsnnhVe7sLIWmYmdPw7x5P0h4W8vUU3Nv1ySgWXtvCz8NizoAEpGXA0sOYoJQV2Rl13LgURAHQ5cI5ILCSA==", - "dev": true, + "version": "0.147.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.147.0.tgz", + "integrity": "sha512-IJ3s6ltHLp45S0bh7phkX+gJO7A1Wuz2EaqpAhb8WjqDwbzMiWKHhyyT42tskaWjEYXtHtVCPpnBJVT9+dcRLg==", + "devOptional": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/Boshen" @@ -2808,17 +2991,215 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@parcel/watcher/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "node_modules/@peculiar/asn1-cms": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.9.4.tgz", + "integrity": "sha512-cben7oxmQsUGZqotus7yt0srYdncOT6RNWcTQ77T2RFOXejYVYkXadrfePdRcrVpO9K95IRLKKglG2k38jKXuw==", + "dev": true, "license": "MIT", - "optional": true, + "peer": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.9.4", + "@peculiar/asn1-x509": "^2.9.4", + "@peculiar/asn1-x509-attr": "^2.9.4", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + }, "engines": { - "node": ">=12" + "node": ">=14" + } + }, + "node_modules/@peculiar/asn1-csr": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.9.4.tgz", + "integrity": "sha512-xd4YN4vpRjkDAQWVfZZkeu12IEND7DOpkqaHSIHxZl1uggUNa9Ju0QxY2jHvDAS9pP0zhRBytg8ifsnGo3V0jw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.9.4", + "@peculiar/asn1-x509": "^2.9.4", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "engines": { + "node": ">=14" + } + }, + "node_modules/@peculiar/asn1-ecc": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.9.4.tgz", + "integrity": "sha512-JJXefFshRAuVAjWQo/39bkg1ywc1VaiO44S8RRC+Ykvf/u2KDmYffoDb0ZBPCR5uJy4AGKQhl8mX+Q8ShcWaXQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.9.4", + "@peculiar/asn1-x509": "^2.9.4", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@peculiar/asn1-pfx": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.9.4.tgz", + "integrity": "sha512-khuGzHTzNzk4GDlIBEILyIs6Lce0yn0ZBdoI9v93kmNncfZRhD+AQ5ODFqdhvoE8cMJF/JMTQ8yA+t1D14kqCw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@peculiar/asn1-cms": "^2.9.4", + "@peculiar/asn1-pkcs8": "^2.9.4", + "@peculiar/asn1-rsa": "^2.9.4", + "@peculiar/asn1-schema": "^2.9.4", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@peculiar/asn1-pkcs8": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.9.4.tgz", + "integrity": "sha512-duRdotlUx9eDZe6QrQpQKl61RbWykCHBCkKayP8V8XdEFwlKHZ8qGGDMyS6Pye7OX7nLFttTTpRkJeet78ckwQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.9.4", + "@peculiar/asn1-x509": "^2.9.4", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@peculiar/asn1-pkcs9": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.9.4.tgz", + "integrity": "sha512-kaL4cNxBpdQE2dKlyZBqz4ygCrwffO+8wfoxTEqM1Z8RadvCeELBRzcv0dzM8aY9azHMwODO5nxU65zXmhToOQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@peculiar/asn1-cms": "^2.9.4", + "@peculiar/asn1-pfx": "^2.9.4", + "@peculiar/asn1-pkcs8": "^2.9.4", + "@peculiar/asn1-schema": "^2.9.4", + "@peculiar/asn1-x509": "^2.9.4", + "@peculiar/asn1-x509-attr": "^2.9.4", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@peculiar/asn1-rsa": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.9.4.tgz", + "integrity": "sha512-pZ96eD1PptovcWQ/GSmuNFXd/7EQJNlKfDaNCyE2rx3W0v6QFelkzquVqRSRyyDXXCYD69ZXJDzZ8GhIiQzKoA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.9.4", + "@peculiar/asn1-x509": "^2.9.4", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@peculiar/asn1-schema": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.9.4.tgz", + "integrity": "sha512-GjzePcT9Iw8NzeOPf73iNS9xM+TBhd/FilAfP+RQGkTMQJTVWtytN3JHJACCjf/ABNau5S7mS3g+DcuxmRgYEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@peculiar/utils": "^2.0.2", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@peculiar/asn1-x509": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.9.4.tgz", + "integrity": "sha512-CxhBo/RdEbMMob7T31ZdQjGuoyRFLVwrDzTn25bihzBasRg9kRm/0IxIPvhgQtcK/9dNcO1XQL2fuPugwELL0Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.9.4", + "@peculiar/utils": "^2.0.2", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@peculiar/asn1-x509-attr": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.9.4.tgz", + "integrity": "sha512-ehQXbpQaQYycgu8OrvigwSPTFfVRcu0ECNYCWw+yzBp02Lw5paRqzzhUpfOgO2K38+WfFZuEz/0RPtam5g0OMg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.9.4", + "@peculiar/asn1-x509": "^2.9.4", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@peculiar/utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@peculiar/utils/-/utils-2.0.3.tgz", + "integrity": "sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/x509": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.3.tgz", + "integrity": "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@peculiar/asn1-cms": "^2.6.0", + "@peculiar/asn1-csr": "^2.6.0", + "@peculiar/asn1-ecc": "^2.6.0", + "@peculiar/asn1-pkcs9": "^2.6.0", + "@peculiar/asn1-rsa": "^2.6.0", + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.0", + "pvtsutils": "^1.3.6", + "reflect-metadata": "^0.2.2", + "tslib": "^2.8.1", + "tsyringe": "^4.10.0" + }, + "engines": { + "node": ">=20.0.0" } }, "node_modules/@pkgjs/parseargs": { @@ -2849,9 +3230,9 @@ } }, "node_modules/@rolldown/binding-android-arm-eabi": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.5.tgz", - "integrity": "sha512-DLe/i+l8ynIBY7XEQ191TeZvCoowIGa18R+dIV30GW7DiOtp74i/xX8hs8GUjW5ARV7VZuie3d6AumSmCwbeRA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.6.tgz", + "integrity": "sha512-b+jTcARdTiFLI6jB4a5XjTm0RWd6KcRfQj/I2356fxUZemiho9zQLxo0RtCuMDAyKcLo6cEltkgbQp6d1+sjjQ==", "cpu": [ "arm" ], @@ -2866,9 +3247,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.5.tgz", - "integrity": "sha512-zXcwKlQApYAOELHd8PwKDFkagYF9Wy4e0RJ+0qnzl9Pjnpj75TEG8ufv40p2J7kCEfwZAsNiuzRIyNNMWT38ig==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.6.tgz", + "integrity": "sha512-lkWU8ZJaRk9q3CIEY1Tc7vIFALp3Xw5NfGJo2hQg5oIqNgxWi1zI+IiDEK3r70BF5Dzol1tcXsnzsRc8NLhG+Q==", "cpu": [ "arm64" ], @@ -2883,9 +3264,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.5.tgz", - "integrity": "sha512-dK4QakI42nzWgJT5sm4y4y/O//D4OxM75/cH28RLV+nzIN9AY+YsbuUVrUTjlLjXR6vpyxFbSsbmNuJ6BP9sww==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.6.tgz", + "integrity": "sha512-dgR56NYnvAszm7Ob1B2/Vn0e8bUQYZH2UjVaMMtMVOCKFSfjhfLmuA/9+O+F+ajUdG6B/bSssrKW6JJYASa8jA==", "cpu": [ "arm64" ], @@ -2900,9 +3281,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.5.tgz", - "integrity": "sha512-fqSALaUu1Wjd1nK2uW2kJDWdLCc8lx1IcY+MTY26Aurfdx19anlzhqXOgCFbBFQnlFDTn4TC1/7Nz4Bl2mLP3A==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.6.tgz", + "integrity": "sha512-vpVxFvUCFioJqug7OTvqptkc4yb8UX0AwfDmJpaR/0sWz+BUmqSVAf7c8JkUgnN8YLspb4a/N6NhTyMAmdyQ7Q==", "cpu": [ "x64" ], @@ -2917,9 +3298,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.5.tgz", - "integrity": "sha512-/vCnNxlkxs9tKxNDcyWUePpJ/PgTzxIaVhoM5SmG8UV+GR/IcPam4VYxi7GIMo7PSDuNqlJqvprqii9NqqVCMw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.6.tgz", + "integrity": "sha512-h1wG6Y6K3JlRswxsI64qQJqBAy4vrLuHgRbc8CZMGSWTOFRY6ghMApM1NKzB2I0n5xV1fjkE18SuVl2QpLeNpA==", "cpu": [ "x64" ], @@ -2934,9 +3315,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.5.tgz", - "integrity": "sha512-abk0NLA519LxRCszmbE0jYKuQ9YPocOXTiOXOo6Yr+YAT95VH+PtqYAjOJvGKt3viEd/x4qzabAlwd5bHOOARg==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.6.tgz", + "integrity": "sha512-tbCiqub0q2MVWJKgF5PoAlNWCtQydiOYSLIkd8sByqK/6MMYLJRcSXSYodqYtd0O+Fw7QaVmKKlS4oL94YRZ0w==", "cpu": [ "arm" ], @@ -2951,9 +3332,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.5.tgz", - "integrity": "sha512-Y7eALiJ8lr0M2HH103Js+g7V34wf6snlpZLAsHI90uLhr3PVlNsbFVAXJC9d/V6BnPyKtpSwI+NcB/RLxsQxuA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.6.tgz", + "integrity": "sha512-oxK9+baEBPhZG5HB4URY+uU04zJWeZlH6Tb9rB5DK4DF9XR1uXNLXt5Q5ZsugTKayNCNLhkcwz/ye74hRI98dg==", "cpu": [ "arm64" ], @@ -2968,9 +3349,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.5.tgz", - "integrity": "sha512-xMvZgnbZg4YVnR/AX2b3oOPDTFYJvUVaJg5FedA/LuvexAtXibZQej4cnTkw3rjsJ/ggUROB64TdtETiim+FYA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.6.tgz", + "integrity": "sha512-muWCk27FVBEZtv0MsK8gnfSmgczA8KQ0uRVJbTABKhkRfQc38aUrcb7fhi3BNiyseFmgcRsoMfQsSNJ+DbZdSw==", "cpu": [ "arm64" ], @@ -2985,9 +3366,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.5.tgz", - "integrity": "sha512-GRjeqTUDHTo5GwntsLaAMcBahG3nlpjftXWZLN73HiYQlhwEowvarFgQnRnQZtIp4keXX7quXFbG38uPZBa2EA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.6.tgz", + "integrity": "sha512-eWDoSfU7Co2qj3vgB3Dt4lj1mG6CoWbcJQkRMP3XJplyCMtuaq3LHvPFjS9QIPvMGWVadJC04Xiy0IdcVPtnwQ==", "cpu": [ "ppc64" ], @@ -3002,9 +3383,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.5.tgz", - "integrity": "sha512-vLNTR45F2Uwc8AufkNXPmB4VliaXs+FvcheEogIzOXzO4l+LzieXF5A/TWxLy5HtqpsRCHUfd0lPVrrdgXdLHQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.6.tgz", + "integrity": "sha512-2bWNjRSIayvupRKxXUY2tWG9fYdoUlTqWywHRvE8Eq3GvuQ+f2HeIkve697fIt+IQs/PV8yFsdWuhp1aJ1PdnA==", "cpu": [ "s390x" ], @@ -3019,9 +3400,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.5.tgz", - "integrity": "sha512-Mgj59/HTuYeK9Gz2MA+mBWKnHsAgkBSec15ZMb1st3oIfFbX7gCjOae7GydHhzcyQi9Z/7M1QuN9bR3oFqF0jQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.6.tgz", + "integrity": "sha512-KekI0gS0wLxe1UBSQSjenBVwou/JkcQPDzBPICGZjxUv9k3RteHDPBQaiOicZUFKRIH2wKEimGwVpnJsbPzu7w==", "cpu": [ "x64" ], @@ -3036,9 +3417,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.5.tgz", - "integrity": "sha512-mY8AP0/ichsbhAxGnLa3d3+MwV0EfgrPND2bplI3Ym8T6R2pJ0N87bvrKVwNXmdy3jnr6eQBecdqx/HMknBmpA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.6.tgz", + "integrity": "sha512-TvtPnfVr+HtyGiDmPK4VWmlNm7QhNNAcK5Q9A7aOXsI8545yCyaoMaicXrFZ72JzeYjaUVk7yT243zT0jzjFKQ==", "cpu": [ "x64" ], @@ -3053,9 +3434,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.5.tgz", - "integrity": "sha512-8SLssA2oweAxyRgDp789ACfRb/3P+zNRJpzZxSizxF9m8NUDQ4+3xjo8ttjhVGGw6Qxb70oZiEtIjaKikCO7Yw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.6.tgz", + "integrity": "sha512-iOo0VEay2XFhaCcH0sps5XIimkSuOnNaZrf6+ZkoSOQBJPKNU48RkmJv0/lSpipexu5P+ouFgafe5IGr/DiQfg==", "cpu": [ "arm64" ], @@ -3070,9 +3451,9 @@ } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.5.tgz", - "integrity": "sha512-vGbruD5zquhoc8D9SViXgN2FBJtNdTyQ4DtG+SWiEGlJiAzoKcZ2xp+xuXCffhubVdt0NJlTZqkeRuERy7g8Cw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.6.tgz", + "integrity": "sha512-y5NTmmasMS455JlOCO4ZM9krIchv3Mvm1crL1iUPGOPgEzSkves9n0SdC5Sjz6+qWDFhd8/JpfWMH8NSWNHe+A==", "cpu": [ "arm64" ], @@ -3087,9 +3468,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.5.tgz", - "integrity": "sha512-e/SXpgISz+IoqVcSSI0rx/d/he8zqLex+/rCWpnHpmVfmPIUjag9H6P7zotf0gJHwPUhQxZ/mF8tr6acebT9yw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.6.tgz", + "integrity": "sha512-np8iZSLfXlAD4kWhiyq/u0Yt8oZDtRQ8lGhQaCXo2rl37KNjeU0GjJuwr4P3oeZ++ROfofsKNBqR5LTO8aXyWQ==", "cpu": [ "x64" ], @@ -3107,7 +3488,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@sindresorhus/base62": { @@ -3164,56 +3545,6 @@ "eslint": "^9.0.0 || ^10.0.0" } }, - "node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.67.0.tgz", - "integrity": "sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@stylistic/eslint-plugin/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@stylistic/eslint-plugin/node_modules/estraverse": { - "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" - } - }, - "node_modules/@stylistic/eslint-plugin/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/@svgdotjs/svg.draggable.js": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/@svgdotjs/svg.draggable.js/-/svg.draggable.js-3.0.6.tgz", @@ -3236,9 +3567,9 @@ } }, "node_modules/@svgdotjs/svg.js": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/@svgdotjs/svg.js/-/svg.js-3.2.7.tgz", - "integrity": "sha512-pxpRccS8zrBl97JkkTzQNqohJ4c3L+xuWH6ulMW9E6yknZ5lp4z+n6MprHNsykFvFj6O8TQJfpsXaTUAJfcUfw==", + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/@svgdotjs/svg.js/-/svg.js-3.2.8.tgz", + "integrity": "sha512-NUdbI/7FDdqGpzKmqr09IQoy9MUcrAC/3bC8gLgXi6OfJuyri450zMLvJekFUhuq3iN5gpdPjoSoStNl9Eijfg==", "license": "MIT", "funding": { "type": "github", @@ -3298,6 +3629,29 @@ "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", "license": "MIT" }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/chai": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", @@ -3309,6 +3663,29 @@ "assertion-error": "^2.0.1" } }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, "node_modules/@types/debug": { "version": "4.1.13", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", @@ -3335,7 +3712,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/estree": { @@ -3353,6 +3730,34 @@ "@types/estree": "*" } }, + "node_modules/@types/express": { + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", + "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "^1" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.9", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.9.tgz", + "integrity": "sha512-QP2ESEe/ImWY0HDwNAnK9PvEffUyhLTnWkk7KXzHfyeWAnlrDe1fN77bXl6ia8KT3wPlmA7t9/VPRpnf4Ex9sg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, "node_modules/@types/hast": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", @@ -3362,6 +3767,25 @@ "@types/unist": "*" } }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.17", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.17.tgz", + "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/jquery": { "version": "3.5.16", "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz", @@ -3371,17 +3795,11 @@ "@types/sizzle": "*" } }, - "node_modules/@types/jsesc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@types/jsesc/-/jsesc-2.5.1.tgz", - "integrity": "sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==", - "license": "MIT" - }, "node_modules/@types/json-schema": { "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, + "devOptional": true, "license": "MIT" }, "node_modules/@types/mdast": { @@ -3393,6 +3811,14 @@ "@types/unist": "*" } }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@types/ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", @@ -3400,10 +3826,10 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "26.1.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.2.tgz", - "integrity": "sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg==", - "dev": true, + "version": "26.4.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.4.0.tgz", + "integrity": "sha512-faiGnoIrLH/V8cibOMEAZ8pMw6oXqSukl29ra4mN8GdaB2ZewzeaLj+INpV5N+Z1eKWzY+IzaIZH2EIR6YZRNQ==", + "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~8.3.0" @@ -3415,6 +3841,22 @@ "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", "license": "MIT" }, + "node_modules/@types/qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@types/react": { "version": "18.3.31", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz", @@ -3425,18 +3867,84 @@ "csstype": "^3.2.2" } }, + "node_modules/@types/retry": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@types/semver": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.8.0.tgz", "integrity": "sha512-1mAINjtQCXXeLkJ9ehXkwOcBpqtLxiVtKhpUf83DdRNdQKV0iXZpaHYqRr7nj+wvxuJzoAmAwXI+sCNMv1CzLQ==", "license": "MIT" }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, "node_modules/@types/sizzle": { "version": "2.3.10", "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.10.tgz", "integrity": "sha512-TC0dmN0K8YcWEAEfiPi5gJP14eJe30TTGjkvek3iM/1NdHHsdCA/Td6GvNndMOo/iSnIsZ4HuuhrYPDAmbxzww==", "license": "MIT" }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", @@ -3456,18 +3964,32 @@ "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", "license": "MIT" }, - "node_modules/@typescript-eslint/parser": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.67.0.tgz", - "integrity": "sha512-fUBfTuuEulWqX6V8+O3PtScV01tzYYRUDTAirHFKoRAt7nOzoGiPt0M/bB47wWNy0coOOcgEwAMUtBpykMxl6w==", + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.67.0", - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/typescript-estree": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0", - "debug": "^4.4.3" + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.68.0.tgz", + "integrity": "sha512-WASHDpCm6qO5jj9g1a+8NiW5+GCkAyLReR56/4VruYmNgfUmqpxOfZ2Yfb8xGfJPWv5Qi6LSD8sXdces3vbp/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.68.0", + "@typescript-eslint/type-utils": "8.68.0", + "@typescript-eslint/utils": "8.68.0", + "@typescript-eslint/visitor-keys": "8.68.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3477,58 +3999,56 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { + "@typescript-eslint/parser": "^8.68.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.67.0.tgz", - "integrity": "sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.7.tgz", + "integrity": "sha512-dML0wP6oak21rsNYCJpJB6O1BJIEwNpGrTw0URPfAk4hm0e3pRfCtzkfB6olBcXcVlU2rouCyz7lCyRB0OMVCA==", "dev": true, "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0" - }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">= 4" } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.67.0.tgz", - "integrity": "sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==", + "node_modules/@typescript-eslint/parser": { + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.68.0.tgz", + "integrity": "sha512-fHq2VC1kpyYfvEcbiMjOpySY4WS7voEp89yAThrHRX5sm9j2lzYppCb2umFMEed4fWcyeLjHxrz0mpjNBaBxMQ==", "dev": true, "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.68.0", + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/typescript-estree": "8.68.0", + "@typescript-eslint/visitor-keys": "8.68.0", + "debug": "^4.4.3" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.67.0.tgz", - "integrity": "sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==", + "node_modules/@typescript-eslint/project-service": { + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.68.0.tgz", + "integrity": "sha512-5GQtWZCXFcFYux955pvoS02WLc49pXNlvIxocKjS0clvwo3in1RdlzVKyiqQH9vE5AKWFLTaUgeQkOrTS+0Qxw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.67.0", - "@typescript-eslint/tsconfig-utils": "8.67.0", - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" + "@typescript-eslint/tsconfig-utils": "^8.68.0", + "@typescript-eslint/types": "^8.68.0", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3541,15 +4061,15 @@ "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.67.0.tgz", - "integrity": "sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.68.0.tgz", + "integrity": "sha512-T5eXpcaJNg8bhjHJ8Rjp68Vq/QBteYtTKY8TZqVNPaUbuz0f6jI9t6aDkylwvalpAB9XTTFeFOjrjXAZ3YvmVA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.67.0", - "eslint-visitor-keys": "^5.0.0" + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/visitor-keys": "8.68.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3559,81 +4079,114 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/parser/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.68.0.tgz", + "integrity": "sha512-F7zrGQfiJHojPwi8vhxZQC1tWtJzvL74cK/nqri2lk8YUXvYaYwl263xOJ69jDWPUk1hmcdoayFwk9lX09npVw==", "dev": true, "license": "MIT", "engines": { - "node": "18 || 20 || >=22" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/parser/node_modules/brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "node_modules/@typescript-eslint/type-utils": { + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.68.0.tgz", + "integrity": "sha512-X77zqoY1EjeWGs/0JNxeaMfp5C5lIz4Tw8y66F1Ne8Faq6g424sBNYM6xBAqElfGZPLpWS+CZAp0DXyKDzWiHg==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^4.0.2" + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/typescript-estree": "8.68.0", + "@typescript-eslint/utils": "8.68.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" }, "engines": { - "node": "20 || >=22" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/parser/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "node_modules/@typescript-eslint/types": { + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.68.0.tgz", + "integrity": "sha512-9RnpsGJjrAllCMefGVVsImJM24YurhC0Q1h4UbvivtvOqXmR/vEJge2OoE++z9m6hyg8T1Q8t5SNT6tHSbrxcg==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/parser/node_modules/minimatch": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", - "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.68.0.tgz", + "integrity": "sha512-OKKsD0tYmoNiU5PW2zehO1yO56jYOm1ShYlxon/Z0SJNidAkdVg86eg9ruRuoXf8xfnuWZGbwDsStkoXbZtIIA==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "brace-expansion": "^5.0.8" + "@typescript-eslint/project-service": "8.68.0", + "@typescript-eslint/tsconfig-utils": "8.68.0", + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/visitor-keys": "8.68.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" }, "engines": { - "node": "18 || 20 || >=22" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/parser/node_modules/ts-api-utils": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", - "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, - "peerDependencies": { - "typescript": ">=4.8.4" + "engines": { + "node": ">=10" } }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.67.0.tgz", - "integrity": "sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==", + "node_modules/@typescript-eslint/utils": { + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.68.0.tgz", + "integrity": "sha512-PB5gJMMOg0Q5P1tsgWtEAqQacJXq0qEqRHDX/YJ4FaTMLfZPpHB3gjl2EJuiZyPABxmj4ZQYiY9m1bdAJ5y7tQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.67.0", - "@typescript-eslint/types": "^8.67.0", - "debug": "^4.4.3" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.68.0", + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/typescript-estree": "8.68.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3643,15 +4196,20 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/project-service/node_modules/@typescript-eslint/types": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.67.0.tgz", - "integrity": "sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.68.0.tgz", + "integrity": "sha512-YR65gGdGvTUAWLldC3xLOvOzamdGzB4A5/N8rehEaHs3Zvoe39BhgY+u0SPch1OvrVTfLcc55wsSgK2NcnTS/A==", "dev": true, "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.68.0", + "eslint-visitor-keys": "^5.0.0" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -3660,21 +4218,17 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.67.0.tgz", - "integrity": "sha512-vV+LUSv5njUWsknE71fqKTlXUva+R76SaeORd6Zojcunk/6DvKFXONU3BrAs2H49mbygUXt6gbYunzwqNwlhdg==", + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" + "url": "https://opencollective.com/eslint" } }, "node_modules/@uiw/codemirror-theme-github": { @@ -3709,9 +4263,9 @@ } }, "node_modules/@ungap/structured-clone": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", - "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", "license": "ISC" }, "node_modules/@vitest/coverage-v8": { @@ -3745,51 +4299,6 @@ } } }, - "node_modules/@vitest/coverage-v8/node_modules/@vitest/pretty-format": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz", - "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/coverage-v8/node_modules/@vitest/utils": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz", - "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.11", - "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/coverage-v8/node_modules/std-env": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", - "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vitest/coverage-v8/node_modules/tinyrainbow": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", - "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@vitest/expect": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz", @@ -3808,16 +4317,6 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/expect/node_modules/tinyrainbow": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", - "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@vitest/mocker": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz", @@ -3868,16 +4367,6 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/pretty-format/node_modules/tinyrainbow": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", - "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@vitest/runner": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz", @@ -3933,16 +4422,6 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/utils/node_modules/tinyrainbow": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", - "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@vue-flow/background": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@vue-flow/background/-/background-1.3.2.tgz", @@ -4066,44 +4545,10 @@ } } }, - "node_modules/@vue-macros/common/node_modules/confbox": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", - "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", - "license": "MIT" - }, - "node_modules/@vue-macros/common/node_modules/local-pkg": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.2.1.tgz", - "integrity": "sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==", - "license": "MIT", - "dependencies": { - "mlly": "^1.7.4", - "pkg-types": "^2.3.0", - "quansync": "^0.2.11" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/@vue-macros/common/node_modules/pkg-types": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz", - "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==", - "license": "MIT", - "dependencies": { - "confbox": "^0.2.4", - "exsolve": "^1.0.8", - "pathe": "^2.0.3" - } - }, "node_modules/@vue/compat": { - "version": "3.5.41", - "resolved": "https://registry.npmjs.org/@vue/compat/-/compat-3.5.41.tgz", - "integrity": "sha512-IjKmvfYfG8ogtCn+TpOucmImKTcXRfokmA0RcO7LECjT2YfD0G3PfGZXiMiaKIEVyqjAzA7Q6luDmk4WsBmwYg==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/compat/-/compat-3.5.42.tgz", + "integrity": "sha512-D4jCfg90ELj47HEDwmhEudQpigGcP6maJ8+nji2p8udMthbfcxn7F98rh3pWMfVuKDnSmSsUUw5jcG+34e7P/Q==", "license": "MIT", "dependencies": { "@babel/parser": "^7.29.8", @@ -4112,7 +4557,7 @@ "source-map-js": "^1.2.1" }, "peerDependencies": { - "vue": "3.5.41" + "vue": "3.5.42" } }, "node_modules/@vue/compiler-core": { @@ -4316,7 +4761,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", @@ -4327,28 +4772,28 @@ "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==", - "dev": true, + "devOptional": true, "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==", - "dev": true, + "devOptional": true, "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==", - "dev": true, + "devOptional": true, "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==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", @@ -4360,14 +4805,14 @@ "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==", - "dev": true, + "devOptional": true, "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==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -4380,7 +4825,7 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" @@ -4390,7 +4835,7 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" @@ -4400,14 +4845,14 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "dev": true, + "devOptional": true, "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==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -4424,7 +4869,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -4438,7 +4883,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -4451,7 +4896,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -4466,7 +4911,7 @@ "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==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -4524,14 +4969,14 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true, + "devOptional": true, "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==", - "dev": true, + "devOptional": true, "license": "Apache-2.0" }, "node_modules/@yr/monotone-cubic-spline": { @@ -4551,6 +4996,45 @@ "node": "^18.17.0 || >=20.5.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==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/acorn": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", @@ -4567,7 +5051,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -4639,7 +5123,7 @@ "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, + "devOptional": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" @@ -4648,14 +5132,31 @@ "ajv": "^8.8.2" } }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "peer": true, + "bin": { + "ansi-html": "bin/ansi-html" + } + }, "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/ansi-styles": { @@ -4674,6 +5175,35 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/anynum": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/anynum/-/anynum-1.0.1.tgz", @@ -4717,6 +5247,14 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/asn1.js": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", @@ -4736,6 +5274,22 @@ "dev": true, "license": "MIT" }, + "node_modules/asn1js": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.10.tgz", + "integrity": "sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.5", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/assert": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", @@ -4864,9 +5418,9 @@ } }, "node_modules/axios": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.19.0.tgz", - "integrity": "sha512-ht/iuYZXEjFxLH/Hkezgd7m6JKlHHXEUSneaDz8uZe1Gj5QZtCnpyDsckvAiEnT89OEbCLmnte4R4sn7P0EKFw==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz", + "integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==", "license": "MIT", "dependencies": { "follow-redirects": "^1.16.0", @@ -4875,6 +5429,33 @@ "proxy-from-env": "^2.1.0" } }, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "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/bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", @@ -4886,10 +5467,14 @@ } }, "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } }, "node_modules/base-64": { "version": "1.0.0", @@ -4919,10 +5504,10 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.11.12", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.12.tgz", - "integrity": "sha512-r7WnVImvVCeFpf2DOXfy41aPWzeNg3H/A2X4dKmy1QL0MSyyk/e7z8ihJ3N6Nn2PsdhkVlqnEfnUE4a05P2aTA==", - "dev": true, + "version": "2.11.20", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.20.tgz", + "integrity": "sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw==", + "devOptional": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -4931,6 +5516,28 @@ "node": ">=6.0.0" } }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bindings": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", @@ -4964,6 +5571,48 @@ "readable-stream": "^3.4.0" } }, + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "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", + "optional": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/bl/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==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/blurhash": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/blurhash/-/blurhash-2.0.5.tgz", @@ -4977,13 +5626,126 @@ "dev": true, "license": "MIT" }, + "node_modules/body-parser": { + "version": "1.20.6", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.6.tgz", + "integrity": "sha512-p5tAzS57i5MV9fZFDj9LeIiTZEufbSe2eDozP+ElheSUq1m74CRq1jI4mYNDdVs9vQztXFLuk/Gd6BWTdwRJ5g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.15.1", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/bonjour-service": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.4.4.tgz", + "integrity": "sha512-jCZcVv7eoc4QesRscwEZtSROBen+6LpKAmBIsQYQrsAeVHLyMXWX/t6eIV5KiRZYNUBl8eVqImEEMQ8L5+c/Kw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true, + "devOptional": true, "license": "ISC" }, + "node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/braces": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", @@ -5004,16 +5766,6 @@ "dev": true, "license": "MIT" }, - "node_modules/browser-resolve": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", - "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve": "^1.17.0" - } - }, "node_modules/browserify-aes": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", @@ -5148,10 +5900,10 @@ } }, "node_modules/browserslist": { - "version": "4.28.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", - "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", - "dev": true, + "version": "4.28.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz", + "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==", + "devOptional": true, "funding": [ { "type": "opencollective", @@ -5168,11 +5920,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.10.44", - "caniuse-lite": "^1.0.30001806", - "electron-to-chromium": "^1.5.393", - "node-releases": "^2.0.51", - "update-browserslist-db": "^1.2.3" + "baseline-browser-mapping": "^2.11.12", + "caniuse-lite": "^1.0.30001809", + "electron-to-chromium": "^1.5.402", + "node-releases": "^2.0.53", + "update-browserslist-db": "^1.3.0" }, "bin": { "browserslist": "cli.js" @@ -5182,9 +5934,9 @@ } }, "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "dev": true, "funding": [ { @@ -5203,14 +5955,14 @@ "license": "MIT", "dependencies": { "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "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==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/buffer-xor": { @@ -5227,12 +5979,51 @@ "dev": true, "license": "MIT" }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/byte-length": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/byte-length/-/byte-length-1.0.2.tgz", "integrity": "sha512-ovBpjmsgd/teRmgcPh23d4gJvxDoXtAzEL9xTfMU8Yc2kqCDb7L9jAG0XHl1nzuGl+h3ebCIF1i62UFyA9V/2Q==", "license": "MIT" }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bytestreamjs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bytestreamjs/-/bytestreamjs-2.0.1.tgz", + "integrity": "sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/cacache": { "version": "19.0.1", "resolved": "https://registry.npmjs.org/cacache/-/cacache-19.0.1.tgz", @@ -5356,10 +6147,10 @@ "license": "MIT" }, "node_modules/caniuse-lite": { - "version": "1.0.30001806", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", - "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", - "dev": true, + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", + "devOptional": true, "funding": [ { "type": "opencollective", @@ -5492,7 +6283,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6.0" @@ -5586,9 +6377,9 @@ "license": "MIT" }, "node_modules/colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.10.0.tgz", + "integrity": "sha512-AidJptpBJmjTclAp9BkLwJi0T93fo5epJnbaZslpg6QVzpHjAiveF55mE9AcUJiGMqRHgMDY8soMsQtuNYMHfw==", "dev": true, "license": "MIT" }, @@ -5641,12 +6432,87 @@ "node": ">= 12.0.0" } }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/confbox": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", - "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", "license": "MIT" }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.8" + } + }, "node_modules/console-browserify": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", @@ -5660,21 +6526,66 @@ "dev": true, "license": "MIT" }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "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" + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "dev": true, + "license": "MIT", + "peer": true }, "node_modules/copy-anything": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", - "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.1.0.tgz", + "integrity": "sha512-ufbM3smX/Jbnpk5wcQjzd1MgBpzmqfNETUAyZNrGwU9foRlyHoGzMMBBCRzEhQLBjZfFDE1W2ufPXX2vdWkV8Q==", "license": "MIT", - "dependencies": { - "is-what": "^5.2.0" - }, "engines": { "node": ">=18" }, @@ -5683,11 +6594,14 @@ } }, "node_modules/core-js": { - "version": "3.49.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz", - "integrity": "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==", + "version": "3.50.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.50.0.tgz", + "integrity": "sha512-BRWgOLKkFeCgRudR6zrs8p9XJZcE14grzKMMssoYrk6krtuEZ7MTKPIY5RzOnqsEKIR9kst7wNzphttraT+Yqw==", "hasInstallScript": true, "license": "MIT", + "engines": { + "node": "*" + }, "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" @@ -5774,13 +6688,6 @@ "sha.js": "^2.4.8" } }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, - "license": "MIT" - }, "node_modules/crelt": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.7.tgz", @@ -5791,7 +6698,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -5884,6 +6791,19 @@ } } }, + "node_modules/css-loader/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/css-tree": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", @@ -5902,7 +6822,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "cssesc": "bin/cssesc" @@ -6115,9 +7035,41 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, + "node_modules/default-browser": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz", + "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -6136,6 +7088,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-properties": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", @@ -6163,6 +7129,17 @@ "node": ">=0.4.0" } }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -6183,6 +7160,18 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, "node_modules/detect-indent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-7.0.2.tgz", @@ -6219,6 +7208,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/devlop": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", @@ -6265,6 +7262,20 @@ "license": "MIT", "optional": true }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", @@ -6294,13 +7305,13 @@ } }, "node_modules/domain-browser": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.22.0.tgz", - "integrity": "sha512-IGBwjF7tNk3cwypFNH/7bfzBcgSCbaMOD3GsaY1AU/JRrnHnYgEM0+9kQt52iZxjNsjBtJYtao146V+f8jFZNw==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-5.7.0.tgz", + "integrity": "sha512-edTFu0M/7wO1pXY6GDxVNVW086uqwWYIHP98txhcPyV995X21JIH2DtYp33sQJOupYoXKe9RwTw2Ya2vWaquTQ==", "dev": true, - "license": "MIT", + "license": "Artistic-2.0", "engines": { - "node": ">=10" + "node": ">=4" }, "funding": { "url": "https://bevry.me/fund" @@ -6381,11 +7392,19 @@ "license": "MIT", "optional": true }, - "node_modules/electron-to-chromium": { - "version": "1.5.399", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.399.tgz", - "integrity": "sha512-lEcqhErbHjXRvd41rnWLpzbyU/IXfIYo7QwaFWmxGeLiLyY2TBCdHnWY88vB+p3ubnihRypDm66panXl7TylLA==", + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/electron-to-chromium": { + "version": "1.5.416", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.416.tgz", + "integrity": "sha512-K6bvB2BjnNrugtIih6ewlbBI9DXa976jIdiIlRLHhBoEI9a4JaQjjHyF+A1IQI543aQYR4LnmOrT/K5fZj0aPA==", + "devOptional": true, "license": "ISC" }, "node_modules/elliptic": { @@ -6432,6 +7451,17 @@ "license": "MIT", "optional": true }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/encoding": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", @@ -6458,7 +7488,7 @@ "version": "5.24.5", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz", "integrity": "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -6540,10 +7570,10 @@ } }, "node_modules/es-module-lexer": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", - "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", - "dev": true, + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", + "devOptional": true, "license": "MIT" }, "node_modules/es-object-atoms": { @@ -6577,7 +7607,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -6593,7 +7623,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=10" @@ -6603,10 +7633,10 @@ } }, "node_modules/eslint": { - "version": "10.9.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.9.0.tgz", - "integrity": "sha512-5KeEOJZBfEVA47boFiBsf+6MmmJpffM7qEBg4pLla2e4nlKgdKlqCW0oSLOGsT8Wl5uCGJptLV1bkaiShj90Gw==", - "dev": true, + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.9.1.tgz", + "integrity": "sha512-9VaAkDURekixUQJy0oJYl2DcN6oKMfxay7XzaGYAWQwsb6qfKf+x76R2k1L8kb1boc+FyCAaTA9GmiKaaiaF+A==", + "devOptional": true, "license": "MIT", "workspaces": [ "packages/*" @@ -6662,13 +7692,13 @@ } }, "node_modules/eslint-config-flat-gitignore": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-flat-gitignore/-/eslint-config-flat-gitignore-2.3.0.tgz", - "integrity": "sha512-bg4ZLGgoARg1naWfsINUUb/52Ksw/K22K+T16D38Y8v+/sGwwIYrGvH/JBjOin+RQtxxC9tzNNiy4shnGtGyyQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/eslint-config-flat-gitignore/-/eslint-config-flat-gitignore-2.4.0.tgz", + "integrity": "sha512-JhYC+V7qEDiCDsbJcVP8fxNc62fk4+i91YLP/YvmVHlkaQ8Xo99olYN8MO5COdxl7onGlsrfZVONe5NYsZP1UA==", "dev": true, "license": "MIT", "dependencies": { - "@eslint/compat": "^2.0.3" + "@eslint/compat": "^2.1.0" }, "funding": { "url": "https://github.com/sponsors/antfu" @@ -6753,178 +7783,12 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.16.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^5.0.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/spdx-expression-parse": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-5.0.0.tgz", - "integrity": "sha512-vngmw3Rgn+o2arXNbnZaj5UtOEBuWBfvaI+Wc8GFfykIhA5/vdK9/Sp/XkLv63dykz2rxKDvKEHupF5P0FORcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/eslint-plugin-perfectionist": { - "version": "5.10.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-perfectionist/-/eslint-plugin-perfectionist-5.10.1.tgz", - "integrity": "sha512-Kprsp9Us0GqAesYaAIzUViw57xYp5WBqzXrcE0Mtww++E5fexWXYBipMuuD7yvyH4vvpBH0+oJ+OMAmZ0oYXkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/utils": "^8.65.0", - "natural-orderby": "^5.0.0" - }, - "engines": { - "node": "^20.0.0 || >=22.0.0" - }, - "peerDependencies": { - "eslint": "^8.45.0 || ^9.0.0 || ^10.0.0" - } - }, - "node_modules/eslint-plugin-perfectionist/node_modules/@typescript-eslint/scope-manager": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.67.0.tgz", - "integrity": "sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-perfectionist/node_modules/@typescript-eslint/types": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.67.0.tgz", - "integrity": "sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-perfectionist/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.67.0.tgz", - "integrity": "sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.67.0", - "@typescript-eslint/tsconfig-utils": "8.67.0", - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/eslint-plugin-perfectionist/node_modules/@typescript-eslint/utils": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.67.0.tgz", - "integrity": "sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.67.0", - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/typescript-estree": "8.67.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/eslint-plugin-perfectionist/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.67.0.tgz", - "integrity": "sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.67.0", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-perfectionist/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/eslint-plugin-perfectionist/node_modules/brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/eslint-plugin-perfectionist/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" }, @@ -6932,40 +7796,52 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-plugin-perfectionist/node_modules/minimatch": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", - "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "node_modules/eslint-plugin-jsdoc/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.8" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=10" } }, - "node_modules/eslint-plugin-perfectionist/node_modules/ts-api-utils": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", - "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "node_modules/eslint-plugin-jsdoc/node_modules/spdx-expression-parse": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-5.0.0.tgz", + "integrity": "sha512-vngmw3Rgn+o2arXNbnZaj5UtOEBuWBfvaI+Wc8GFfykIhA5/vdK9/Sp/XkLv63dykz2rxKDvKEHupF5P0FORcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/eslint-plugin-perfectionist": { + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-perfectionist/-/eslint-plugin-perfectionist-5.10.1.tgz", + "integrity": "sha512-Kprsp9Us0GqAesYaAIzUViw57xYp5WBqzXrcE0Mtww++E5fexWXYBipMuuD7yvyH4vvpBH0+oJ+OMAmZ0oYXkw==", "dev": true, "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.65.0", + "natural-orderby": "^5.0.0" + }, "engines": { - "node": ">=18.12" + "node": "^20.0.0 || >=22.0.0" }, "peerDependencies": { - "typescript": ">=4.8.4" + "eslint": "^8.45.0 || ^9.0.0 || ^10.0.0" } }, "node_modules/eslint-plugin-vue": { "version": "10.10.0", "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.10.0.tgz", "integrity": "sha512-dL9x9rBHqqNcByWiLOHK6L0SB97V82/NC0cZRn9cXPjM7pCuWlpQQP9bFH4vjBv80ej1ZpzAkuD8zWH1o9bZbA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", @@ -6993,25 +7869,56 @@ } } }, + "node_modules/eslint-plugin-vue/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "devOptional": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "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==", - "dev": true, + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=8.0.0" + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/ajv": { "version": "6.15.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -7024,53 +7931,11 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/eslint/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", - "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@types/esrecurse": "^4.3.1", - "@types/estree": "^1.0.8", - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/eslint/node_modules/eslint-visitor-keys": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" @@ -7083,7 +7948,7 @@ "version": "11.2.0", "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.16.0", @@ -7097,44 +7962,18 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/estraverse": { - "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" - } - }, "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, + "devOptional": true, "license": "MIT" }, - "node_modules/eslint/node_modules/minimatch": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", - "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.8" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/espree": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.15.0", @@ -7148,24 +7987,11 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/esquery": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" @@ -7174,21 +8000,11 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "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" - } - }, "node_modules/esrecurse": { "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, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -7197,21 +8013,11 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "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" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -7237,12 +8043,33 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/eventemitter3": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", @@ -7253,7 +8080,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.8.x" @@ -7299,6 +8126,102 @@ "license": "Apache-2.0", "optional": true }, + "node_modules/express": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", + "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.5", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.15.1", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/express/node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/exsolve": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.1.1.tgz", @@ -7351,20 +8274,20 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", - "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.6.tgz", + "integrity": "sha512-7Ical1vFEMr0onbVzEDIreM22I4khW+fzyQPwvAFWBp1iwdshSZRsL4jjRvPG9JP1uiqMHRto+YU6R2/CzDz5Q==", "funding": [ { "type": "github", @@ -7378,9 +8301,25 @@ "license": "BSD-3-Clause" }, "node_modules/fast-xml-builder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.3.0.tgz", - "integrity": "sha512-F74cZEdCvuw9P41GAC3rod4X04jjWGM1JPEv/GWSqFTWLsdyMSBMBMlm9Hk3GLBgLBbdBNY8yee0pQh2RBVESQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.3.1.tgz", + "integrity": "sha512-pIM/1n3ntFXKYrUZwW7QCK0gAW7XY+wzj1YMIV3tLDvPj/V+zTGJK5e3/4WJfwj0qWw2ElNXiTixda/R+3YSug==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.6.2", + "xml-naming": "^0.3.0" + } + }, + "node_modules/fast-xml-parser": { + "version": "5.11.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.11.1.tgz", + "integrity": "sha512-TBw6K/fxoQGGjCmZDw9w/ZwP3uDcnTM4YH/g+PFRWr8sbe5idXtxNN6vITh4+1ruCZaho6uBFurElsA7F0zzgw==", "funding": [ { "type": "github", @@ -7389,8 +8328,15 @@ ], "license": "MIT", "dependencies": { + "@nodable/entities": "^3.0.0", + "fast-xml-builder": "^1.2.0", + "is-unsafe": "^2.0.0", "path-expression-matcher": "^1.6.2", + "strnum": "^2.4.2", "xml-naming": "^0.3.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" } }, "node_modules/fastest-levenshtein": { @@ -7404,15 +8350,29 @@ } }, "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.3.tgz", + "integrity": "sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==", "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" } }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -7457,7 +8417,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "flat-cache": "^4.0.0" @@ -7466,20 +8426,6 @@ "node": ">=16.0.0" } }, - "node_modules/file-entry-cache/node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, "node_modules/file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -7501,11 +8447,50 @@ "node": ">=8" } }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/find-up": { "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, + "devOptional": true, "license": "MIT", "dependencies": { "locate-path": "^6.0.0", @@ -7529,22 +8514,24 @@ } }, "node_modules/flat-cache": { - "version": "6.1.23", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.23.tgz", - "integrity": "sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==", - "dev": true, + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "devOptional": true, "license": "MIT", "dependencies": { - "cacheable": "^2.5.0", - "flatted": "^3.4.2", - "hookified": "^1.15.0" + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" } }, "node_modules/flatted": { "version": "3.4.4", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/floating-vue": { @@ -7666,6 +8653,28 @@ "node": ">=12.20.0" } }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -7827,7 +8836,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -7836,6 +8845,32 @@ "node": ">=10.13.0" } }, + "node_modules/glob-to-regex.js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/glob-to-regex.js/-/glob-to-regex.js-1.2.0.tgz", + "integrity": "sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/glob/node_modules/brace-expansion": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", @@ -7905,10 +8940,23 @@ "which": "bin/which" } }, + "node_modules/globals": { + "version": "17.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.11.0.tgz", + "integrity": "sha512-Z2I8hM+PbJDXQDq3Icgpzv+mPdwr68iZUU9d5WW4FuXfDUQfkZaZuvjMv42/5crNyw154+9+VWXbYrUgDXbxNw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/globby": { - "version": "16.2.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-16.2.3.tgz", - "integrity": "sha512-VZX7TV7jmd/pn71vdnLKtgwy1IWqc3KjI9x1/UtPkwoKk5fKrNLY30ltDe3cAM5xruIN7YuuaulFt133jRrKZg==", + "version": "16.2.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-16.2.4.tgz", + "integrity": "sha512-c8B/VNLmxRcmqqenRA9t+9IyOjf9+V6lTxPaUJLqOCONdQkWZ0ETYgX0qbtJqPsgCNusT9MZ5Jeidw8Eb9tn2g==", "dev": true, "license": "MIT", "dependencies": { @@ -7916,6 +8964,7 @@ "fast-glob": "^3.3.3", "ignore": "^7.0.5", "is-path-inside": "^4.0.0", + "micromatch": "^4.0.8", "slash": "^5.1.0", "unicorn-magic": "^0.4.0" }, @@ -7927,9 +8976,9 @@ } }, "node_modules/globby/node_modules/ignore": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", - "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.7.tgz", + "integrity": "sha512-dML0wP6oak21rsNYCJpJB6O1BJIEwNpGrTw0URPfAk4hm0e3pRfCtzkfB6olBcXcVlU2rouCyz7lCyRB0OMVCA==", "dev": true, "license": "MIT", "engines": { @@ -7959,7 +9008,7 @@ "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, + "devOptional": true, "license": "ISC" }, "node_modules/gridstack": { @@ -7978,11 +9027,19 @@ ], "license": "MIT" }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true, + "license": "MIT", + "peer": true + }, "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==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -8155,9 +9212,9 @@ } }, "node_modules/highlight.js": { - "version": "11.11.1", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", - "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", + "version": "11.11.2", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.2.tgz", + "integrity": "sha512-oaXMACAU0kzOMXBjWpNcX+vlwSBCIAiZ9BHa7gA15NOTtT2L/l8OSZDuqS2XppOhZBPJ7hm4o8ep2kyuip2uEQ==", "license": "BSD-3-Clause", "engines": { "node": ">=12.0.0" @@ -8201,12 +9258,80 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/hot-patcher": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/hot-patcher/-/hot-patcher-2.0.1.tgz", "integrity": "sha512-ECg1JFG0YzehicQaogenlcs2qg6WsXQsxtnbr1i696u5tLUjtJdQAh0u2g0Q5YV45f263Ta1GnUJsc8WIfJf4Q==", "license": "MIT" }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/hpack.js/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==", + "dev": true, + "license": "MIT", + "peer": true, + "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/hpack.js/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==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/hpack.js/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==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/html-entities": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", @@ -8285,6 +9410,60 @@ "license": "BSD-2-Clause", "optional": true }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -8311,6 +9490,54 @@ "node": ">= 14" } }, + "node_modules/http-proxy-middleware": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.10.tgz", + "integrity": "sha512-RKzRWNPxUZqbuk3BC5mGVJbBnWgr+diEnjJexIOytFbBzDy88Fbh/YvBr3DsNrl1jYAfjWfpATEv0NO35FDuPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/http-proxy/node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/https-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", @@ -8331,6 +9558,17 @@ "node": ">= 6" } }, + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10.18" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -8383,7 +9621,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 4" @@ -8447,7 +9685,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -8484,9 +9722,9 @@ } }, "node_modules/ip-address": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.4.0.tgz", - "integrity": "sha512-oSK96Grm3aP6OrS263xVxbNDGVL7rzBtYdpGqlDG8iQdoenDoTs/nkki+DflYbAEE8Xl6o5YxhxlrKvI3nqKXQ==", + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.0.tgz", + "integrity": "sha512-BGFsyJd5mpXp3rK6jIdADLNgpJUK1jnjzvYF8lK+VyDab9JAmqN0YOKDdP17HlgKb2+ehPgDc8EtnRLbGCAMhA==", "dev": true, "license": "MIT", "optional": true, @@ -8494,6 +9732,17 @@ "node": ">= 12" } }, + "node_modules/ipaddr.js": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.5.0.tgz", + "integrity": "sha512-aq+t5NAc+cS6rZQQVWC2x98CPqGtKKTMDd4Gaodv0wShnItdKg/51djkGJ1hqH+Oy0ivDftCbSLCQob8zso01w==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 10" + } + }, "node_modules/is-absolute-url": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", @@ -8554,6 +9803,20 @@ "dev": true, "license": "MIT" }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -8599,6 +9862,23 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -8662,6 +9942,26 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-nan": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", @@ -8679,6 +9979,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-network-error": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.2.tgz", + "integrity": "sha512-PhBY86zaxNZUuWP6h13Vu5oFe0XY6/UlKzQnYFELzGVHygP3MxmvTfYSG7GN3aIab/iWudSMgjSnG9Dq+nHrgA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -8702,10 +10016,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.1.0.tgz", + "integrity": "sha512-bUi/yjmtKYcRVUtWRGr0UA6xEFh2I6zWUwMrUXB3s7bmYCaZ8a+0ZsTRkrawh/mzlSD1Y0Ph8bp/U+TvBpWDNw==", "dev": true, "license": "MIT", "engines": { @@ -8763,9 +10089,9 @@ } }, "node_modules/is-unsafe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-unsafe/-/is-unsafe-2.0.0.tgz", - "integrity": "sha512-2LdV822R+wmI86unXA93WCFpL6g+av8ynWk0nrHyJqGop5VoocYsSLFgN8jrfalT6iGeLNM4KXuVSsULP53kEA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-unsafe/-/is-unsafe-2.0.2.tgz", + "integrity": "sha512-HgbIHPBH0KHHCcjLfGsCvhtPTVxjaAZlXjwdz7/GQC40SjSe4sfQsar8J5VFo8JOSbarkpV0OLG95bbaNd9aAQ==", "funding": [ { "type": "github", @@ -8774,16 +10100,21 @@ ], "license": "MIT" }, - "node_modules/is-what": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", - "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, "license": "MIT", + "peer": true, + "dependencies": { + "is-inside-container": "^1.0.0" + }, "engines": { - "node": ">=18" + "node": ">=16" }, "funding": { - "url": "https://github.com/sponsors/mesqueeb" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/isarray": { @@ -8797,7 +10128,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/isobject": { @@ -8810,16 +10141,6 @@ "node": ">=0.10.0" } }, - "node_modules/isomorphic-timers-promises": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/isomorphic-timers-promises/-/isomorphic-timers-promises-1.0.1.tgz", - "integrity": "sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", @@ -8880,7 +10201,7 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -8895,7 +10216,7 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -8915,9 +10236,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "dev": true, "funding": [ { @@ -8951,6 +10272,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -8963,7 +10285,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/json-parse-even-better-errors": { @@ -8983,13 +10305,14 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -9002,7 +10325,7 @@ "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "json-buffer": "3.0.1" @@ -9025,6 +10348,18 @@ "dev": true, "license": "MIT" }, + "node_modules/launch-editor": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.14.1.tgz", + "integrity": "sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "picocolors": "^1.1.1", + "shell-quote": "^1.8.4" + } + }, "node_modules/layerr": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/layerr/-/layerr-3.0.0.tgz", @@ -9050,7 +10385,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", @@ -9082,7 +10417,7 @@ "version": "1.33.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", - "dev": true, + "devOptional": true, "license": "MPL-2.0", "dependencies": { "detect-libc": "^2.0.3" @@ -9352,11 +10687,28 @@ "integrity": "sha512-P8aEP5U/D1/IlTY2OeYsErdwh9bGuLE30NcXtKEjgdHcahveQoQwM2yZNsioQHsWFz0P7KKudisbrzCgR0sDHg==", "license": "MIT" }, + "node_modules/local-pkg": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.2.1.tgz", + "integrity": "sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==", + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/locate-path": { "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, + "devOptional": true, "license": "MIT", "dependencies": { "p-locate": "^5.0.0" @@ -9407,13 +10759,13 @@ } }, "node_modules/lru-cache": { - "version": "11.5.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", - "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "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": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" } }, "node_modules/magic-string": { @@ -9468,6 +10820,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/make-fetch-happen": { "version": "14.0.3", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz", @@ -9493,9 +10858,9 @@ } }, "node_modules/marked": { - "version": "18.0.9", - "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.9.tgz", - "integrity": "sha512-/Sa4qiiHZxf0/FQdBBowr9q4r10krCwMvpK48FUBdXdUXScDxiQGR9zCPrFgRVR5LU3iySOiIjy09ZQvADir1w==", + "version": "18.0.11", + "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.11.tgz", + "integrity": "sha512-HnslJfsZkRPBDJRHvVtAaWlZHEpSu7u8LgQuJCELjRKuWR+hpq4A7sLq3p8HaI9ypVoXDXxV34CsQJEe1+J5Aw==", "license": "MIT", "bin": { "marked": "bin/marked.js" @@ -9769,6 +11134,45 @@ "dev": true, "license": "CC0-1.0" }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "4.68.2", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.68.2.tgz", + "integrity": "sha512-Un1ElEBoIdPI9kg0sm3LebVEuEViodfIvlaG8Z1MFXa7ZnR9vWuPKUo3dt/vuWY2ivc05l76B5QOjdgCzAzmGw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@jsonjoy.com/fs-core": "4.68.2", + "@jsonjoy.com/fs-fsa": "4.68.2", + "@jsonjoy.com/fs-node": "4.68.2", + "@jsonjoy.com/fs-node-builtins": "4.68.2", + "@jsonjoy.com/fs-node-to-fsa": "4.68.2", + "@jsonjoy.com/fs-node-utils": "4.68.2", + "@jsonjoy.com/fs-print": "4.68.2", + "@jsonjoy.com/fs-snapshot": "4.68.2", + "@jsonjoy.com/json-pack": "^1.11.0", + "@jsonjoy.com/util": "^1.9.0", + "glob-to-regex.js": "^1.0.1", + "thingies": "^2.5.0", + "tree-dump": "^1.0.3", + "tslib": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + } + }, "node_modules/meow": { "version": "14.1.0", "resolved": "https://registry.npmjs.org/meow/-/meow-14.1.0.tgz", @@ -9782,11 +11186,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/merge-stream": { "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, + "devOptional": true, "license": "MIT" }, "node_modules/merge2": { @@ -9799,6 +11214,17 @@ "node": ">= 8" } }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/micromark": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", @@ -10255,6 +11681,19 @@ "node": ">=8.6" } }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/miller-rabin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", @@ -10276,6 +11715,20 @@ "dev": true, "license": "MIT" }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -10325,6 +11778,22 @@ "dev": true, "license": "MIT" }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "devOptional": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -10337,16 +11806,16 @@ } }, "node_modules/minimizer-webpack-plugin": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.6.1.tgz", - "integrity": "sha512-DoeAZz8Q1C1znwsUzej1fdoi4jCf7/+Em27ouLqfK/+3m8G+D7yDhUwrc3CNhjSzGUN1kn7Iv4sWmjflQHenpw==", - "dev": true, + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.8.0.tgz", + "integrity": "sha512-2cT9+goJfBhtMz+gJqejSf09ClgmYhPhccRb/fb0ztVbixt0BkO8mRuI26FoPPuUNkRk6iEDryWAIouc5W8eJA==", + "devOptional": true, "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", + "@jridgewell/trace-mapping": "^0.3.31", "jest-worker": "^27.4.5", - "schema-utils": "^4.3.0", - "terser": "^5.31.1" + "schema-utils": "^4.3.3", + "terser": "^5.51.0" }, "engines": { "node": ">= 10.13.0" @@ -10589,6 +12058,23 @@ "ufo": "^1.6.3" } }, + "node_modules/mlly/node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "license": "MIT" + }, + "node_modules/mlly/node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, "node_modules/moo": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.3.tgz", @@ -10609,6 +12095,21 @@ "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", "license": "MIT" }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, "node_modules/nan": { "version": "2.22.2", "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.2.tgz", @@ -10618,9 +12119,9 @@ "optional": true }, "node_modules/nanoid": { - "version": "3.3.17", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.17.tgz", - "integrity": "sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==", + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "funding": [ { "type": "github", @@ -10647,7 +12148,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/natural-orderby": { @@ -10693,14 +12194,21 @@ "optional": true }, "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz", + "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==", "dev": true, "license": "MIT", "optional": true, + "dependencies": { + "content-type": "^2.1.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/neo-async": { @@ -10716,9 +12224,9 @@ "license": "MIT" }, "node_modules/node-abi": { - "version": "3.94.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.94.0.tgz", - "integrity": "sha512-W5ZNO5KRPB5TkYmGVD9F6YqhsglXJzE6etpbmT+f6EQElhiX/UTG551cnsRGvLG3fyZEg9HwaDmNmj5nwJ4z9g==", + "version": "3.96.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.96.0.tgz", + "integrity": "sha512-rebQ/lz7i0EkoLzUVSrKRzA69zMkwLp95kKMWoMDkkM00Suxz0D7zEQPwRml5fQum24mj7bPvmlgLAmu2JCiYg==", "dev": true, "license": "MIT", "optional": true, @@ -10729,6 +12237,20 @@ "node": ">=10" } }, + "node_modules/node-abi/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "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", @@ -10811,6 +12333,20 @@ "node": ">=18" } }, + "node_modules/node-gyp/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/node-gyp/node_modules/which": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", @@ -10829,91 +12365,54 @@ } }, "node_modules/node-polyfill-webpack-plugin": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/node-polyfill-webpack-plugin/-/node-polyfill-webpack-plugin-4.1.0.tgz", - "integrity": "sha512-b4ei444EKkOagG/yFqojrD3QTYM5IOU1f8tn9o6uwrG4qL+brI7oVhjPVd0ZL2xy+Z6CP5bu9w8XTvlWgiXHcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "node-stdlib-browser": "^1.3.0", - "type-fest": "^4.27.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "webpack": ">=5" - } - }, - "node_modules/node-releases": { - "version": "2.0.51", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", - "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/node-stdlib-browser": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-stdlib-browser/-/node-stdlib-browser-1.3.1.tgz", - "integrity": "sha512-X75ZN8DCLftGM5iKwoYLA3rjnrAEs97MkzvSd4q2746Tgpg8b8XWiBGiBG4ZpgcAqBgtgPHTiAc8ZMCvZuikDw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/node-polyfill-webpack-plugin/-/node-polyfill-webpack-plugin-4.0.0.tgz", + "integrity": "sha512-WLk77vLpbcpmTekRj6s6vYxk30XoyaY5MDZ4+9g8OaKoG3Ij+TjOqhpQjVUlfDZBPBgpNATDltaQkzuXSnnkwg==", "dev": true, "license": "MIT", "dependencies": { - "assert": "^2.0.0", - "browser-resolve": "^2.0.0", + "assert": "^2.1.0", "browserify-zlib": "^0.2.0", - "buffer": "^5.7.1", - "console-browserify": "^1.1.0", + "buffer": "^6.0.3", + "console-browserify": "^1.2.0", "constants-browserify": "^1.0.0", - "create-require": "^1.1.1", - "crypto-browserify": "^3.12.1", - "domain-browser": "4.22.0", - "events": "^3.0.0", + "crypto-browserify": "^3.12.0", + "domain-browser": "^5.7.0", + "events": "^3.3.0", "https-browserify": "^1.0.0", - "isomorphic-timers-promises": "^1.0.1", "os-browserify": "^0.3.0", "path-browserify": "^1.0.1", - "pkg-dir": "^5.0.0", "process": "^0.11.10", - "punycode": "^1.4.1", + "punycode": "^2.3.1", "querystring-es3": "^0.2.1", - "readable-stream": "^3.6.0", + "readable-stream": "^4.5.2", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.1", - "url": "^0.11.4", - "util": "^0.12.4", - "vm-browserify": "^1.0.1" + "string_decoder": "^1.3.0", + "timers-browserify": "^2.0.12", + "tty-browserify": "^0.0.1", + "type-fest": "^4.18.2", + "url": "^0.11.3", + "util": "^0.12.5", + "vm-browserify": "^1.1.2" }, "engines": { - "node": ">=10" + "node": ">=14" + }, + "peerDependencies": { + "webpack": ">=5" } }, - "node_modules/node-stdlib-browser/node_modules/pkg-dir": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", - "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", - "dev": true, + "node_modules/node-releases": { + "version": "2.0.54", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz", + "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==", + "devOptional": true, "license": "MIT", - "dependencies": { - "find-up": "^5.0.0" - }, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/node-stdlib-browser/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==", - "dev": true, - "license": "MIT" - }, "node_modules/nopt": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", @@ -10946,6 +12445,19 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -10966,7 +12478,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" @@ -11043,6 +12555,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/obug": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", @@ -11057,6 +12577,31 @@ "node": ">=12.20.0" } }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -11068,11 +12613,31 @@ "wrappy": "1" } }, + "node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "deep-is": "^0.1.3", @@ -11103,7 +12668,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -11119,7 +12684,7 @@ "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, + "devOptional": true, "license": "MIT", "dependencies": { "p-limit": "^3.0.2" @@ -11132,9 +12697,9 @@ } }, "node_modules/p-map": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.6.tgz", - "integrity": "sha512-I4Prw6ivkd6p8PiYR1tXASOAOBzIJwu0TB7fqaX0c/8c3QAehNYmX57EijyGGGBt3c/BIowGwV03RVBtXvHEVg==", + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.7.tgz", + "integrity": "sha512-VaWRu2i4FJNRtiRWCuuQRgfQ1B7a6+gMSrO+3j0EQi/k0ULfS9kosRxGoiqwzIjZTDI02tGfk5mXXltLg6QtfQ==", "dev": true, "license": "MIT", "optional": true, @@ -11161,6 +12726,36 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-retry": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", + "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/p-timeout": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.1.tgz", @@ -11296,6 +12891,17 @@ "dev": true, "license": "MIT" }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", @@ -11307,7 +12913,7 @@ "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, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -11332,7 +12938,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -11377,6 +12983,14 @@ "license": "ISC", "optional": true }, + "node_modules/path-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/pathe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", @@ -11414,13 +13028,12 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -11517,14 +13130,33 @@ } }, "node_modules/pkg-types": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", - "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz", + "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==", "license": "MIT", "dependencies": { - "confbox": "^0.1.8", - "mlly": "^1.7.4", - "pathe": "^2.0.1" + "confbox": "^0.2.4", + "exsolve": "^1.0.8", + "pathe": "^2.0.3" + } + }, + "node_modules/pkijs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.4.0.tgz", + "integrity": "sha512-emEcLuomt2j03vxD54giVB4SxTjnsqkU692xZOZXHDVoYyypEm+b3jpiTcc+Cf+myooc+/Ly0z01jqeNHVgJGw==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@noble/hashes": "1.4.0", + "asn1js": "^3.0.6", + "bytestreamjs": "^2.0.1", + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=16.0.0" } }, "node_modules/playwright": { @@ -11620,23 +13252,6 @@ "dev": true, "license": "MIT" }, - "node_modules/postcss-html/node_modules/postcss-safe-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", - "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.3.3" - } - }, "node_modules/postcss-media-query-parser": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", @@ -11715,30 +13330,20 @@ "license": "MIT" }, "node_modules/postcss-safe-parser": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", - "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", + "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "license": "MIT", "engines": { - "node": ">=18.0" + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.3.3" } }, "node_modules/postcss-scss": { @@ -11772,7 +13377,7 @@ "version": "7.1.5", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.5.tgz", "integrity": "sha512-KvvtD7SrlBP7dlgkBghEE3r84CABm5SmV2aNcG4oCA+qDnJ/tvKonFVvwWAyyWUEwxuNawdfEAZKP9zM3oZ2Uw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -11822,7 +13427,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 0.8.0" @@ -11844,22 +13449,57 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/prettier-plugin-packagejson": { - "version": "2.5.22", - "resolved": "https://registry.npmjs.org/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.22.tgz", - "integrity": "sha512-G6WalmoUssKF8ZXkni0+n4324K+gG143KPysSQNW+FrR0XyNb3BdRxchGC/Q1FE/F702p7/6KU7r4mv0WSWbzA==", + "node_modules/prettier-plugin-packagejson": { + "version": "2.5.22", + "resolved": "https://registry.npmjs.org/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.22.tgz", + "integrity": "sha512-G6WalmoUssKF8ZXkni0+n4324K+gG143KPysSQNW+FrR0XyNb3BdRxchGC/Q1FE/F702p7/6KU7r4mv0WSWbzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "sort-package-json": "3.6.0" + }, + "peerDependencies": { + "prettier": ">= 1.16.0" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, + "node_modules/prettier-plugin-packagejson/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prettier-plugin-packagejson/node_modules/sort-package-json": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/sort-package-json/-/sort-package-json-3.6.0.tgz", + "integrity": "sha512-fyJsPLhWvY7u2KsKPZn1PixbXp+1m7V8NWqU8CvgFRbMEX41Ffw1kD8n0CfJiGoaSfoAvbrqRRl/DcHO8omQOQ==", "dev": true, "license": "MIT", "dependencies": { - "sort-package-json": "3.6.0" + "detect-indent": "^7.0.2", + "detect-newline": "^4.0.1", + "git-hooks-list": "^4.1.1", + "is-plain-obj": "^4.1.0", + "semver": "^7.7.3", + "sort-object-keys": "^2.0.1", + "tinyglobby": "^0.2.15" }, - "peerDependencies": { - "prettier": ">= 1.16.0" + "bin": { + "sort-package-json": "cli.js" }, - "peerDependenciesMeta": { - "prettier": { - "optional": true - } + "engines": { + "node": ">=20" } }, "node_modules/proc-log": { @@ -11916,9 +13556,9 @@ } }, "node_modules/prosemirror-commands": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz", - "integrity": "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.2.tgz", + "integrity": "sha512-q6Q6szxqdu9Xd6EcdKsqXghu5nQdZTpB4Q9yd04WRc7/jt763e/rT60Owh0L1GYY+T46o5rD+9lEN36dZS43tw==", "license": "MIT", "dependencies": { "prosemirror-model": "^1.0.0", @@ -11988,9 +13628,9 @@ } }, "node_modules/prosemirror-view": { - "version": "1.42.2", - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.42.2.tgz", - "integrity": "sha512-Pdg0l5kXm8aLDquFAnQFTCITg0q44sLqBlHlpsVLD9segdOao8TOfQdAhCrCXyVgPSRr6UDDROOIWA3bIrN9YQ==", + "version": "1.42.3", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.42.3.tgz", + "integrity": "sha512-oTN7EtH+CpwxU9NrwEYWd0UZ4JUx7l048l5A2Xppm4p/60isZYLnth9QVQmC3VRIvdrIWCxwZSd+Uz791G31/w==", "license": "MIT", "dependencies": { "prosemirror-model": "^1.25.8", @@ -11998,6 +13638,32 @@ "prosemirror-transform": "^1.1.0" } }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/proxy-from-env": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", @@ -12045,12 +13711,34 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/pvtsutils": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/pvutils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.2.0.tgz", + "integrity": "sha512-BbubeCEyTuQjVMakvJQ/Sxbc93F2pwmbsxONT/ZRrwU7Ua38d8unYTwXpTVLAKJ4BDuH9IGztCjQcd/N/39Dvg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/qified": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/qified/-/qified-0.10.1.tgz", @@ -12072,9 +13760,9 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.15.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", - "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -12184,6 +13872,48 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -12201,36 +13931,27 @@ "rc": "cli.js" } }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "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==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" }, "engines": { - "node": ">= 6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/readdirp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", - "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", "license": "MIT", "engines": { "node": ">= 20.19.0" @@ -12253,6 +13974,14 @@ "node": ">= 10.13.0" } }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "dev": true, + "license": "Apache-2.0", + "peer": true + }, "node_modules/rehype-external-links": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/rehype-external-links/-/rehype-external-links-3.0.0.tgz", @@ -12562,13 +14291,13 @@ "license": "MIT" }, "node_modules/rolldown": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.5.tgz", - "integrity": "sha512-VD2IE5PUG4Oj8zz2VGykiYd5wbnjdIiSsNQb8Qu5B+noEp+A78mu2iVvpp27g8es14Tk9rofNs5Tku9iQCS4fA==", - "dev": true, + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.6.tgz", + "integrity": "sha512-vMM4q3aixf46GiF1Kok8jDPFsEpXgFWGjUHXNkNHNm+Y2adXAG2dbX91jkti3i0ZRsOlcmbuzAz1poObSHCmUA==", + "devOptional": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.146.0", + "@oxc-project/types": "=0.147.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -12578,21 +14307,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm-eabi": "1.2.5", - "@rolldown/binding-android-arm64": "1.2.5", - "@rolldown/binding-darwin-arm64": "1.2.5", - "@rolldown/binding-darwin-x64": "1.2.5", - "@rolldown/binding-freebsd-x64": "1.2.5", - "@rolldown/binding-linux-arm-gnueabihf": "1.2.5", - "@rolldown/binding-linux-arm64-gnu": "1.2.5", - "@rolldown/binding-linux-arm64-musl": "1.2.5", - "@rolldown/binding-linux-ppc64-gnu": "1.2.5", - "@rolldown/binding-linux-s390x-gnu": "1.2.5", - "@rolldown/binding-linux-x64-gnu": "1.2.5", - "@rolldown/binding-linux-x64-musl": "1.2.5", - "@rolldown/binding-openharmony-arm64": "1.2.5", - "@rolldown/binding-win32-arm64-msvc": "1.2.5", - "@rolldown/binding-win32-x64-msvc": "1.2.5" + "@rolldown/binding-android-arm-eabi": "1.2.6", + "@rolldown/binding-android-arm64": "1.2.6", + "@rolldown/binding-darwin-arm64": "1.2.6", + "@rolldown/binding-darwin-x64": "1.2.6", + "@rolldown/binding-freebsd-x64": "1.2.6", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.6", + "@rolldown/binding-linux-arm64-gnu": "1.2.6", + "@rolldown/binding-linux-arm64-musl": "1.2.6", + "@rolldown/binding-linux-ppc64-gnu": "1.2.6", + "@rolldown/binding-linux-s390x-gnu": "1.2.6", + "@rolldown/binding-linux-x64-gnu": "1.2.6", + "@rolldown/binding-linux-x64-musl": "1.2.6", + "@rolldown/binding-openharmony-arm64": "1.2.6", + "@rolldown/binding-win32-arm64-msvc": "1.2.6", + "@rolldown/binding-win32-x64-msvc": "1.2.6" } }, "node_modules/rope-sequence": { @@ -12601,6 +14330,20 @@ "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==", "license": "MIT" }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -12669,8 +14412,7 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/sass": { "version": "1.103.1", @@ -12745,7 +14487,7 @@ "version": "4.3.3", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", @@ -12765,7 +14507,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -12796,16 +14538,182 @@ "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", "license": "MIT" }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/selfsigned": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-5.5.0.tgz", + "integrity": "sha512-ftnu3TW4+3eBfLRFnDEkzGxSF/10BJBkaLJuBHZX0kiPS7bRdlpZGu6YGt4KngMkdTwJE6MbjavFpqHvqVt+Ew==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@peculiar/x509": "^1.14.2", + "pkijs": "^3.3.3" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "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" + } + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" }, "engines": { - "node": ">=10" + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/serve-index": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.2.tgz", + "integrity": "sha512-KDj11HScOaLmrPxl70KYNW1PksP4Nb/CLL2yvC+Qd2kHMPEEpfc4Re2e4FOay+bC/+XQl/7zAcWON3JVo5v3KQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "accepts": "~1.3.8", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.8.0", + "mime-types": "~2.1.35", + "parseurl": "~1.3.3" + }, + "engines": { + "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" } }, "node_modules/set-function-length": { @@ -12833,6 +14741,14 @@ "dev": true, "license": "MIT" }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC", + "peer": true + }, "node_modules/sha.js": { "version": "2.4.12", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", @@ -12871,7 +14787,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -12884,12 +14800,26 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/shell-quote": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.10.0.tgz", + "integrity": "sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/side-channel": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", @@ -13092,6 +15022,19 @@ "node": ">=0.10" } }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, "node_modules/socks": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", @@ -13143,9 +15086,9 @@ "license": "MIT" }, "node_modules/sort-package-json": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/sort-package-json/-/sort-package-json-3.6.0.tgz", - "integrity": "sha512-fyJsPLhWvY7u2KsKPZn1PixbXp+1m7V8NWqU8CvgFRbMEX41Ffw1kD8n0CfJiGoaSfoAvbrqRRl/DcHO8omQOQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/sort-package-json/-/sort-package-json-4.0.0.tgz", + "integrity": "sha512-6aYOlYI9AWioZ+rzu+4zKLmoFqJP0/fHDxrd7X04yqEibikY+5YVF0EYlyGn4v6X2PJY7yAUWV7oeP+i5rOm/g==", "dev": true, "license": "MIT", "dependencies": { @@ -13161,20 +15104,20 @@ "sort-package-json": "cli.js" }, "engines": { - "node": ">=20" + "node": ">=22" } }, - "node_modules/sort-package-json/node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "node_modules/sort-package-json/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=10" } }, "node_modules/sortablejs": { @@ -13187,7 +15130,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -13206,7 +15149,7 @@ "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==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -13270,6 +15213,56 @@ "dev": true, "license": "CC0-1.0" }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/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==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/speakingurl": { "version": "14.0.1", "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", @@ -13312,6 +15305,24 @@ "dev": true, "license": "MIT" }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", + "dev": true, + "license": "MIT" + }, "node_modules/stream-browserify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", @@ -13323,6 +15334,21 @@ "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==", + "dev": true, + "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", @@ -13336,6 +15362,21 @@ "xtend": "^4.0.2" } }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -13382,6 +15423,17 @@ "node": ">=8" } }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -13390,35 +15442,18 @@ "license": "MIT", "optional": true }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "ansi-regex": "^6.2.2" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=8" } }, "node_modules/stringify-entities": { @@ -13436,16 +15471,19 @@ } }, "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "ansi-regex": "^6.2.2" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/strip-ansi-cjs": { @@ -13463,12 +15501,49 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/striptags": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/striptags/-/striptags-3.2.0.tgz", "integrity": "sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw==", "license": "MIT" }, + "node_modules/strnum": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.2.tgz", + "integrity": "sha512-rDG3Ah4TV0k1hWvLSzkZtMmLN9+eS+h3knq4MP6A42Y3Yh5qGNnOUs1jJkoSr8FG5dsL28c7KgkIBzSEykqtuw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "anynum": "^1.0.1" + } + }, "node_modules/strtok3": { "version": "10.3.5", "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.5.tgz", @@ -13672,6 +15747,19 @@ "stylelint": ">=14.0.0" } }, + "node_modules/stylelint-config-recommended-vue/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/stylelint-scss": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-7.2.0.tgz", @@ -13711,19 +15799,6 @@ "stylelint": ">= 11 < 18" } }, - "node_modules/stylelint/node_modules/ansi-regex": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", - "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/stylelint/node_modules/file-entry-cache": { "version": "11.1.5", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.5.tgz", @@ -13734,16 +15809,55 @@ "flat-cache": "^6.1.23" } }, + "node_modules/stylelint/node_modules/flat-cache": { + "version": "6.1.23", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.23.tgz", + "integrity": "sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cacheable": "^2.5.0", + "flatted": "^3.4.2", + "hookified": "^1.15.0" + } + }, "node_modules/stylelint/node_modules/ignore": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", - "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.7.tgz", + "integrity": "sha512-dML0wP6oak21rsNYCJpJB6O1BJIEwNpGrTw0URPfAk4hm0e3pRfCtzkfB6olBcXcVlU2rouCyz7lCyRB0OMVCA==", "dev": true, "license": "MIT", "engines": { "node": ">= 4" } }, + "node_modules/stylelint/node_modules/postcss-safe-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", + "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, "node_modules/stylelint/node_modules/string-width": { "version": "8.2.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz", @@ -13761,22 +15875,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/stylelint/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/superjson": { "version": "2.2.6", "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", @@ -13887,6 +15985,16 @@ "node": ">=10.0.0" } }, + "node_modules/table/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/table/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -13909,11 +16017,24 @@ "node": ">=8" } }, + "node_modules/table/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tapable": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -13981,6 +16102,22 @@ "node": ">=6" } }, + "node_modules/tar-stream/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==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/tar/node_modules/yallist": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", @@ -13993,10 +16130,10 @@ } }, "node_modules/terser": { - "version": "5.49.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.49.0.tgz", - "integrity": "sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA==", - "dev": true, + "version": "5.51.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.51.2.tgz", + "integrity": "sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==", + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -14076,9 +16213,35 @@ "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==", - "dev": true, + "devOptional": true, "license": "MIT" }, + "node_modules/thingies": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.6.1.tgz", + "integrity": "sha512-cV/CMGTK3M4MlnJ/0At6ismOw/A0EEniDNScajjz/Br3c1sqE72YD01rGpPTKwd27wAxI5Pr+6+0w8yofzFRYw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "^2" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/timers-browserify": { "version": "2.0.12", "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", @@ -14125,16 +16288,14 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "node_modules/tinyrainbow": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", + "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", + "dev": true, "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "node": ">=14.0.0" } }, "node_modules/to-buffer": { @@ -14182,6 +16343,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tree-dump": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz", + "integrity": "sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, "node_modules/tributejs": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/tributejs/-/tributejs-5.1.3.tgz", @@ -14208,344 +16398,208 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/ts-md5": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ts-md5/-/ts-md5-2.0.1.tgz", - "integrity": "sha512-yF35FCoEOFBzOclSkMNEUbFQZuv89KEQ+5Xz03HrMSGUGB1+r+El+JiGOFwsP4p9RFNzwlrydYoTLvPOuICl9w==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typed-array-buffer": { - "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", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.67.0.tgz", - "integrity": "sha512-S2udFs8tCKEKffuJ4TB1idGUZiXdCPGi3IPBGWXarbLQ5UPXORV8QEVzJ4gCRduURMb5EkpNCdjbk0eDIuI8Yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.67.0", - "@typescript-eslint/parser": "8.67.0", - "@typescript-eslint/typescript-estree": "8.67.0", - "@typescript-eslint/utils": "8.67.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.67.0.tgz", - "integrity": "sha512-Un7Heoyj65NREbKAyIrFxeM143NZpExWmy1Nep4DLeQOeLlTeumPjoNKnBrU5D5moWXbPJgRa5Uwcdu0faVNGQ==", + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.67.0", - "@typescript-eslint/type-utils": "8.67.0", - "@typescript-eslint/utils": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.5.0" - }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=18.12" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.67.0", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.67.0.tgz", - "integrity": "sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "typescript": ">=4.8.4" } }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.67.0.tgz", - "integrity": "sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==", + "node_modules/ts-loader": { + "version": "9.6.2", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.6.2.tgz", + "integrity": "sha512-R4iuczmtgxvtuI556s+hTZ6/7Ee03VCAk/l/M8LY1OAsUgB7YydsCxkgq9D9pKRaD7GJqUi2u8fp9zZP/ufjKA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/typescript-estree": "8.67.0", - "@typescript-eslint/utils": "8.67.0", - "debug": "^4.4.3", - "ts-api-utils": "^2.5.0" + "chalk": "^4.1.0", + "picomatch": "^4.0.0", + "source-map": "^0.7.4" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=12.0.0" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.67.0.tgz", - "integrity": "sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "loader-utils": "*", + "typescript": "*", + "webpack": "^4.0.0 || ^5.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependenciesMeta": { + "loader-utils": { + "optional": true + } } }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.67.0.tgz", - "integrity": "sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==", + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.67.0", - "@typescript-eslint/tsconfig-utils": "8.67.0", - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, + "license": "BSD-3-Clause", + "peer": true, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" + "node": ">= 12" } }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.67.0.tgz", - "integrity": "sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.67.0", - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/typescript-estree": "8.67.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" + "node_modules/ts-md5": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ts-md5/-/ts-md5-2.0.1.tgz", + "integrity": "sha512-yF35FCoEOFBzOclSkMNEUbFQZuv89KEQ+5Xz03HrMSGUGB1+r+El+JiGOFwsP4p9RFNzwlrydYoTLvPOuICl9w==", + "license": "MIT", + "engines": { + "node": ">=18" } }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.67.0.tgz", - "integrity": "sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==", + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "peer": true + }, + "node_modules/tsyringe": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz", + "integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@typescript-eslint/types": "8.67.0", - "eslint-visitor-keys": "^5.0.0" + "tslib": "^1.9.3" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">= 6.0.0" } }, - "node_modules/typescript-eslint/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "node_modules/tsyringe/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true, - "license": "MIT", + "license": "0BSD", + "peer": 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==", + "dev": true, + "license": "MIT" + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, "engines": { - "node": "18 || 20 || >=22" + "node": "*" } }, - "node_modules/typescript-eslint/node_modules/brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", - "dev": true, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "devOptional": true, "license": "MIT", "dependencies": { - "balanced-match": "^4.0.2" + "prelude-ls": "^1.2.1" }, "engines": { - "node": "20 || >=22" + "node": ">= 0.8.0" } }, - "node_modules/typescript-eslint/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", "dev": true, - "license": "Apache-2.0", + "license": "(MIT OR CC0-1.0)", "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "node": ">=16" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/typescript-eslint/node_modules/ignore": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", - "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, "license": "MIT", + "peer": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, "engines": { - "node": ">= 4" + "node": ">= 0.6" } }, - "node_modules/typescript-eslint/node_modules/minimatch": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", - "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "node_modules/typed-array-buffer": { + "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": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "brace-expansion": "^5.0.8" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" }, "engines": { - "node": "18 || 20 || >=22" + "node": ">= 0.4" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": ">=14.17" } }, - "node_modules/typescript-eslint/node_modules/ts-api-utils": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", - "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "node_modules/typescript-eslint": { + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.68.0.tgz", + "integrity": "sha512-MHy0Y0ynqeEbx/S45+i/bBssdy3X6KNBfmJAP35GrgtNxu2TQ5K5xsFDhAnmsq1jvpdoZOPG1LGtJo0HWqYCrQ==", "dev": true, "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.68.0", + "@typescript-eslint/parser": "8.68.0", + "@typescript-eslint/typescript-estree": "8.68.0", + "@typescript-eslint/utils": "8.68.0" + }, "engines": { - "node": ">=18.12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/typescript-event-target": { @@ -14564,7 +16618,7 @@ "version": "8.3.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/unicorn-magic": { @@ -14599,18 +16653,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unified/node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/unique-filename": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-4.0.0.tgz", @@ -14734,6 +16776,17 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/unplugin": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.3.0.tgz", @@ -14804,35 +16857,11 @@ "url": "https://github.com/sponsors/sxzz" } }, - "node_modules/unplugin-utils/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/unplugin/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/update-browserslist-db": { - "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, + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz", + "integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==", + "devOptional": true, "funding": [ { "type": "opencollective", @@ -14863,7 +16892,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" @@ -14927,9 +16956,32 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, + "devOptional": true, "license": "MIT" }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -14952,6 +17004,17 @@ "spdx-license-ids": "^3.0.0" } }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", @@ -14984,7 +17047,7 @@ "version": "8.2.2", "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz", "integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "lightningcss": "^1.33.0", @@ -15073,19 +17136,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/vite/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/vitest": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz", @@ -15176,36 +17226,6 @@ } } }, - "node_modules/vitest/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/vitest/node_modules/std-env": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", - "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", - "dev": true, - "license": "MIT" - }, - "node_modules/vitest/node_modules/tinyrainbow": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", - "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/vm-browserify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", @@ -15235,16 +17255,13 @@ } }, "node_modules/vue-codemirror6": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/vue-codemirror6/-/vue-codemirror6-1.6.1.tgz", - "integrity": "sha512-0Ue6nWy055UKP/6LkT0I7nW5SRSFJ+3mokwBdHePQsj11T02mrg3A0jtHyBqH23nRHQFxd3NKw63sZJ1ygo5dA==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/vue-codemirror6/-/vue-codemirror6-1.6.2.tgz", + "integrity": "sha512-U7XdFCKbLDuCGrfH+bCFbWbSPBAhEFrBYLBOrtimB/yvMtmslwabZzO4iLqutA8UBb37SQ6B+Cwj1QmCDuGxng==", "license": "MIT", "dependencies": { "vue-demi": "latest" }, - "engines": { - "node": "^22.18.0 || >=24.12.0" - }, "peerDependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/commands": "^6.0.0", @@ -15288,7 +17305,7 @@ "version": "10.4.1", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.4.1.tgz", "integrity": "sha512-Gk6gRDj0n/fkRa3C3l0bBheoBckUq/Rs0F/TvMWIS6nzzx67amAViMe9CkNgsP2tXyQONvGiHQESHwFtZ3aYDA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -15308,46 +17325,17 @@ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0" } }, - "node_modules/vue-eslint-parser/node_modules/eslint-scope": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", - "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@types/esrecurse": "^4.3.1", - "@types/estree": "^1.0.8", - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/vue-eslint-parser/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/vue-eslint-parser/node_modules/estraverse": { - "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", + "node_modules/vue-eslint-parser/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "devOptional": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, "engines": { - "node": ">=4.0" + "node": ">=10" } }, "node_modules/vue-loader": { @@ -15441,7 +17429,7 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.2.tgz", "integrity": "sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.1.2" @@ -15450,6 +17438,17 @@ "node": ">=10.13.0" } }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, "node_modules/web-streams-polyfill": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", @@ -15484,6 +17483,12 @@ "node": ">=14" } }, + "node_modules/webdav/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, "node_modules/webdav/node_modules/brace-expansion": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", @@ -15505,29 +17510,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/webdav/node_modules/fast-xml-parser": { - "version": "5.10.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.10.1.tgz", - "integrity": "sha512-IEMIf7298kXuZSRFoGfMYrl7is8LpavODgbNz1cwIudv7KwVFnuU+UsMporfq6PD6aXSlawZlARiA3UywCTfMw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "license": "MIT", - "dependencies": { - "@nodable/entities": "^3.0.0", - "fast-xml-builder": "^1.2.0", - "is-unsafe": "^2.0.0", - "path-expression-matcher": "^1.6.2", - "strnum": "^2.4.1", - "xml-naming": "^0.3.0" - }, - "bin": { - "fxparser": "src/cli/cli.js" - } - }, "node_modules/webdav/node_modules/minimatch": { "version": "9.0.9", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", @@ -15543,26 +17525,11 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/webdav/node_modules/strnum": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.1.tgz", - "integrity": "sha512-M9eUSMT2dCB2cTNPG7UYj6KuK7RJR2SN2+yCV/fTW3xzTCS6EaGZ5pSMgDIjB7r8zSfTGk+dvvn9rTjpVS9Mwg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "license": "MIT", - "dependencies": { - "anynum": "^1.0.1" - } - }, "node_modules/webpack": { - "version": "5.109.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.109.2.tgz", - "integrity": "sha512-U9/cvLzxObKNEZ9+TtdqrHM5/9z3lgl2c+c4BzbqGxFQvQvBAq87yql5A8pQ+rrMbS496MZJeF5enVBndIy2hw==", - "dev": true, + "version": "5.110.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.110.2.tgz", + "integrity": "sha512-TciLrfM7zgEjqGdY851HkirDsSPQgTFsWQpl9oHqMAMYsHhEC0bKjscvjpnz+pzx10hLC8qISApGrsnrCP4UtQ==", + "devOptional": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.8", @@ -15575,11 +17542,10 @@ "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.24.4", "es-module-lexer": "^2.1.0", - "eslint-scope": "5.1.1", "events": "^3.2.0", "graceful-fs": "^4.2.11", "mime-db": "^1.54.0", - "minimizer-webpack-plugin": "^5.6.1", + "minimizer-webpack-plugin": "^5.7.0", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", @@ -15655,6 +17621,193 @@ "node": ">=18" } }, + "node_modules/webpack-dev-middleware": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.5.tgz", + "integrity": "sha512-uxQ6YqGdE4hgDKNf7hUiPXOdtkXvBJXrfEGYSx7P7LC8hnUYGK70X6xQXUvXeNyBDDcsiQXpG2m3G9vxowaEuA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^4.43.1", + "mime-types": "^3.0.1", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware/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==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/webpack-dev-server": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.6.tgz", + "integrity": "sha512-HNLRmamRvVavZQ+avceZifmv8hmdUjg43t6MI4SqJDwFdW7RPQwH5vzGhDRZSX59SgfbeHhLnq3g+uooWo7pVw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.25", + "@types/express-serve-static-core": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", + "colorette": "^2.0.10", + "compression": "^1.8.1", + "connect-history-api-fallback": "^2.0.0", + "express": "^4.22.1", + "graceful-fs": "^4.2.6", + "http-proxy-middleware": "^2.0.9", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.14.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "schema-utils": "^4.2.0", + "selfsigned": "^5.5.0", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^7.4.2", + "ws": "^8.18.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/webpack-dev-server/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/webpack-dev-server/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/webpack-dev-server/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/webpack-merge": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", @@ -15674,7 +17827,7 @@ "version": "3.5.1", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.1.tgz", "integrity": "sha512-jyuiGJdtvY434z5bUZrjz67v76/ePNvFZTp9Mdz29IlH4+GPsgyGjiv0fKI+M7BdkU6ADjulUcKAd3tUK3WlEw==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=10.13.0" @@ -15690,17 +17843,44 @@ "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 0.6" } }, + "node_modules/websocket-driver": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.5.tgz", + "integrity": "sha512-ZL2+3c7kMBdIRCMz6l8jQMHyGVxj+UL+xVk74Ombiciboca8rHa15L86B19E5oh1pL9Ii/uj54gtsIrZGMo6zA==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -15762,7 +17942,7 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -15807,6 +17987,17 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -15831,18 +18022,18 @@ "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "optional": true, - "engines": { - "node": ">=12" + "dependencies": { + "ansi-regex": "^5.0.1" }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "engines": { + "node": ">=8" } }, "node_modules/wrap-ansi/node_modules/ansi-styles": { @@ -15859,23 +18050,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -15897,11 +18071,51 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/ws": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/xml-name-validator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=18" @@ -15955,26 +18169,11 @@ "dev": true, "license": "ISC" }, - "node_modules/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "node_modules/yocto-queue": { "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, + "devOptional": true, "license": "MIT", "engines": { "node": ">=10" diff --git a/package.json b/package.json index a5674a0ed..dc7e030c5 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "css-loader": "~7.1.5", "eslint": "^10.9.0", "eslint-config-prettier": "^10.1.8", - "node-polyfill-webpack-plugin": "4.1.0", + "node-polyfill-webpack-plugin": "4.0.0", "postcss-html": "^1.0.0", "prettier": "^3.9.6", "style-loader": "~4.0.0", diff --git a/tests/e2e/spec-coverage/example-set-setup-step.spec.ts b/tests/e2e/spec-coverage/example-set-setup-step.spec.ts index 63b5eeacb..f6271821a 100644 --- a/tests/e2e/spec-coverage/example-set-setup-step.spec.ts +++ b/tests/e2e/spec-coverage/example-set-setup-step.spec.ts @@ -117,9 +117,7 @@ test.describe('example sets', () => { ) }) - test('setup status offers the sets the app actually ships', async ({ - page, - }) => { + test('setup status offers the sets the app actually ships', async ({ page }) => { const res = await api(page, 'GET', `${BASE}/api/setup/status`) const profiles = res.json?.profiles ?? [] @@ -210,9 +208,7 @@ test.describe('example sets', () => { ).toBe(true) }) - test('re-loading is safe, because the step promises it is', async ({ - page, - }) => { + test('re-loading is safe, because the step promises it is', async ({ page }) => { // The step body tells the operator it is "safe to run more than once". // That sentence is a contract; this asserts the server keeps it rather // than erroring or reporting failure on a second pass. From 2076df8690e39c2e56eb4ebab19c2bfaf3fd2517 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Mon, 31 Aug 2026 04:51:29 +0200 Subject: [PATCH 10/21] chore(deps): @conduction/nextcloud-vue 2.25.0 -> 2.25.1 (#1038) Picks up the fix for the Buildiq edit button. This app was pinned to 2.25.0, which looks current but does not contain the fix: 2.25.0 still carries `useAppStatus('openbuild')`, and the app id moved to `buildiq`, so the `OC.appswebroots` lookup missed and the button rendered nothing. No error, no failed request, no console warning. The fix landed in 2.25.1. Lockfile edited surgically rather than regenerated, so only version, resolved and integrity move. The integrity hash was checked against the published tarball bytes. --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 102b05795..fad79c088 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.0", "license": "EUPL-1.2", "dependencies": { - "@conduction/nextcloud-vue": "^2.24.2", + "@conduction/nextcloud-vue": "^2.25.1", "@nextcloud/auth": "^2.6.0", "@nextcloud/axios": "~2.5.2", "@nextcloud/capabilities": "^1.2.1", @@ -562,9 +562,9 @@ } }, "node_modules/@conduction/nextcloud-vue": { - "version": "2.25.0", - "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-2.25.0.tgz", - "integrity": "sha512-a0xWo7fRiq9OnuYfxx7lADY1cg6z9C+KwSR5JNI8fk88vgFUAiQOWwx3k0zE97IsyhOtkzfB3uZEd2gtPO2S1Q==", + "version": "2.25.1", + "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-2.25.1.tgz", + "integrity": "sha512-c5sY4XnHrfGUIUEatJEIT5jK78k9REj2UCqXylbHiDPkv1HpUx7Sf3XtfDxAd4xPjn/kbO094rNqShK4tPnY7w==", "license": "EUPL-1.2", "dependencies": { "@ckpack/vue-color": "^1.6.0", diff --git a/package.json b/package.json index dc7e030c5..e362dd17c 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "extends @nextcloud/browserslist-config" ], "dependencies": { - "@conduction/nextcloud-vue": "^2.24.2", + "@conduction/nextcloud-vue": "^2.25.1", "@nextcloud/auth": "^2.6.0", "@nextcloud/axios": "~2.5.2", "@nextcloud/capabilities": "^1.2.1", From dad55340f48ffb8d314fb0369347e7a27b5d01d8 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Mon, 31 Aug 2026 05:00:53 +0200 Subject: [PATCH 11/21] feat(governance): add the cross-app command seam for governance bodies (#1019) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(governance): add the cross-app command seam for governance bodies decidiq#874 made GovernanceBody able to hold a Dutch bezwaaradviescommissie and added a REST write path for it. That path is the door for EXTERNAL callers. An in-process app-to-app command cannot use it: ADR-041 says a cross-app command travels as a typed event (gate-27 enforces it), and an in-process HTTP call to our own instance has no session, so ApiController::write() refuses it — which is exactly the state a background migration runs in. So this adds the missing door, copying the DecisionRequestedEvent shape: - GovernanceBodyRequestedEvent / GovernanceBodyCreatedEvent - GovernanceBodyCommandService — the idempotent upsert plus the roster fan-out to Person + Membership - GovernanceBodyRequestedListener, registered beside registerDecisionEvents - sourceApp + externalReference on GovernanceBody, additively Every write is preceded by a resolve. The body resolves on (sourceApp, externalReference), a Person on nextcloudUserId, a Membership on its (person, governanceBody) pair, so a re-run of a consuming migration updates rather than minting a second of each. The body is saved and its id read BEFORE the first membership write, so a crash mid-fan-out leaves a body the next run completes instead of orphans pointing at nothing. `active` is refused when absent rather than defaulted to true: it is the one field the consuming app throws on, and a silent default would route objections to a disbanded committee with nothing erroring. Every idempotency test calls the seam TWICE and counts rows. A test that calls it once sees a body either way and cannot tell an idempotent write from a duplicating one. Mutation-checked: making findBody() always miss, making the Person lookup always miss, and defaulting `active` to true each turn the suite red. ApprovalRouteStore is renamed RegisterObjectStore. It was already generic (save/findAll/normalise over decidiq's register) and this change is its second consumer; a second copy would have been the "second store that drifts" hazard in miniature. Unblocks dossiq's migrate-committees-to-decidiq, which is BLOCKED on precisely this seam and asks nothing else of decidiq. Verified: 1241 unit tests pass (22 skipped, pre-existing), PHPCS/PHPMD/PHPStan/ Psalm clean on every changed file, and all 73 applicable hydra gates green including gate-27 no-phantom-cross-app-rpc. * fix(ci): give the cross-app listeners their own registrar, and catalogue the two new schema titles Two real CI failures on this branch, both caused by it. phpmd: adding a second event/listener pair took DomainServiceRegistrar to a coupling of 14, over the threshold — measured 0 on development. The registrar's job is registration, so the coupling is inherent; the fix is that the inbound cross-app surface is its own concern. CrossAppEventRegistrar now holds it as one map in one file, which also means adding a command is one line. This extraction was already in the stacked approval-route PR. It belongs here instead: this is the branch where the threshold is first crossed, and a stacked PR must not be what makes its parent green. check:schema-l10n: `Source app` and `External reference` are new schema property titles with no catalogue key, so they would render in English inside an otherwise translated form. Added to en.json and nl.json and rebuilt the js catalogues. The ratchet is back to its 1634 baseline. The third red check, "Conflict markers and PHP syntax", was CANCELLED rather than failed — it re-runs on this push. Verified at CI SCOPE, not just on the changed files: phpmd, phpcs, phpstan and psalm clean across the whole tree, 1241 unit tests pass, and all four npm checks pass. check:manifest needs Ajv resolvable; without it the script silently falls back to a structural lint and reports a PRE-EXISTING page-type finding, which is worth knowing before someone reads that fallback as a regression. * fix(l10n): catalogue three schema descriptions development left uncovered The merge brought in schema strings with no catalogue key, which would render in English inside an otherwise translated form: the tender `awardedTo` and `referenceNumber` descriptions and the ORI `schemaOrgType` one. This is pre-existing debt rather than something this branch introduced — origin/development measures 1637 uncovered against a 1634 baseline on its own, so the check is red there too. Catalogued rather than worked around, which puts the count at 1632 and lets the ratchet come DOWN two. Baseline lowered accordingly, which is what the checker asks for when the count improves. * fix(ci): clear three checks that are red on development itself decidiq's development branch currently fails five Code Quality jobs. Three of them showed up on this PR and none of the three is this branch's doing, so they are fixed here rather than reported as inherited: - Frontend Check (format): tests/e2e/spec-coverage/example-set-setup-step.spec.ts was not prettier-formatted. Formatted. - Hydra Gates (gate-102 manifest-l10n-coverage): six manifest strings from development's example-set setup step had no nl.json key, so they rendered English to a Dutch user. Catalogued and rebuilt; the gate now passes and all 75 applicable gates are green. - Frontend Check (check:l10n-js): nl.js was behind nl.json. The l10n:build above brings them back in sync. The fourth, Integration Tests (Newman), is NOT fixed here and is not mine: one assertion expects `process-templates` to contain the built-in `association-alv` slug and gets an empty list. That is ProcessTemplate SEEDING, which this branch does not touch, and it fails identically on development. Left alone rather than patched blind — a seeding fix belongs with whoever changed the templates, and guessing at it from here would be a change nobody could review against intent. The fifth, E2E Tests (Playwright), is likewise pre-existing on development. --------- Co-authored-by: Ruben van der Linde --- l10n/.schema-l10n-baseline.json | 2 +- l10n/en.js | 13 +- l10n/en.json | 13 +- l10n/nl.js | 13 +- l10n/nl.json | 13 +- lib/AppInfo/Application.php | 5 +- .../Registrar/CrossAppEventRegistrar.php | 81 ++++ .../Registrar/DomainServiceRegistrar.php | 25 - lib/Event/GovernanceBodyCreatedEvent.php | 121 +++++ lib/Event/GovernanceBodyRequestedEvent.php | 306 ++++++++++++ .../GovernanceBodyRequestedListener.php | 131 +++++ lib/Service/ApprovalRouteService.php | 4 +- lib/Service/GovernanceBodyCommandService.php | 415 ++++++++++++++++ ...RouteStore.php => RegisterObjectStore.php} | 19 +- .../register.d/71-governance-body-events.json | 26 + .../governance-body-events/proposal.md | 107 +++++ .../specs/governance-body-events/spec.md | 117 +++++ .../changes/governance-body-events/tasks.md | 43 ++ .../GovernanceBodyRequestedListenerTest.php | 205 ++++++++ .../Unit/Service/ApprovalRouteServiceTest.php | 4 +- .../GovernanceBodyCommandServiceTest.php | 453 ++++++++++++++++++ 21 files changed, 2074 insertions(+), 42 deletions(-) create mode 100644 lib/AppInfo/Registrar/CrossAppEventRegistrar.php create mode 100644 lib/Event/GovernanceBodyCreatedEvent.php create mode 100644 lib/Event/GovernanceBodyRequestedEvent.php create mode 100644 lib/Listener/GovernanceBodyRequestedListener.php create mode 100644 lib/Service/GovernanceBodyCommandService.php rename lib/Service/{ApprovalRouteStore.php => RegisterObjectStore.php} (84%) create mode 100644 lib/Settings/register.d/71-governance-body-events.json create mode 100644 openspec/changes/governance-body-events/proposal.md create mode 100644 openspec/changes/governance-body-events/specs/governance-body-events/spec.md create mode 100644 openspec/changes/governance-body-events/tasks.md create mode 100644 tests/Unit/Listener/GovernanceBodyRequestedListenerTest.php create mode 100644 tests/Unit/Service/GovernanceBodyCommandServiceTest.php diff --git a/l10n/.schema-l10n-baseline.json b/l10n/.schema-l10n-baseline.json index b01d4fbd3..d880fe418 100644 --- a/l10n/.schema-l10n-baseline.json +++ b/l10n/.schema-l10n-baseline.json @@ -1,3 +1,3 @@ { - "uncovered": 1634 + "uncovered": 1632 } diff --git a/l10n/en.js b/l10n/en.js index feb315f5f..86879498e 100644 --- a/l10n/en.js +++ b/l10n/en.js @@ -1738,7 +1738,18 @@ OC.L10N.register( "No meetings": "No meetings", "Previous month": "Previous month", "Table": "Table", - "Today": "Today" + "Today": "Today", + "Source app": "Source app", + "External reference": "External reference", + "consultationType=tender: the winning party recorded when the award decision is made (status=awarded). Decidiq owns publish/manage/award only; authoring is procest and bidding is pipelinq.": "consultationType=tender: the winning party recorded when the award decision is made (status=awarded). Decidiq owns publish/manage/award only; authoring is procest and bidding is pipelinq.", + "schema.org annotation matching the ORI type (ChooseAction / Event / CreativeWork).": "schema.org annotation matching the ORI type (ChooseAction / Event / CreativeWork).", + "consultationType=tender: public tender reference/notice number.": "consultationType=tender: public tender reference/notice number.", + "Association or VvE": "Association or VvE", + "Company board": "Company board", + "Every schema, generated values": "Every schema, generated values", + "Municipality": "Municipality", + "None, I will set this up myself": "None, I will set this up myself", + "Works council": "Works council" }, "nplurals=2; plural=(n != 1);" ) diff --git a/l10n/en.json b/l10n/en.json index 0dbd12c4f..ec7a986ff 100644 --- a/l10n/en.json +++ b/l10n/en.json @@ -1737,7 +1737,18 @@ "No meetings": "No meetings", "Previous month": "Previous month", "Table": "Table", - "Today": "Today" + "Today": "Today", + "Source app": "Source app", + "External reference": "External reference", + "consultationType=tender: the winning party recorded when the award decision is made (status=awarded). Decidiq owns publish/manage/award only; authoring is procest and bidding is pipelinq.": "consultationType=tender: the winning party recorded when the award decision is made (status=awarded). Decidiq owns publish/manage/award only; authoring is procest and bidding is pipelinq.", + "schema.org annotation matching the ORI type (ChooseAction / Event / CreativeWork).": "schema.org annotation matching the ORI type (ChooseAction / Event / CreativeWork).", + "consultationType=tender: public tender reference/notice number.": "consultationType=tender: public tender reference/notice number.", + "Association or VvE": "Association or VvE", + "Company board": "Company board", + "Every schema, generated values": "Every schema, generated values", + "Municipality": "Municipality", + "None, I will set this up myself": "None, I will set this up myself", + "Works council": "Works council" }, "pluralForm": "nplurals=2; plural=(n != 1);" } diff --git a/l10n/nl.js b/l10n/nl.js index 39bb1714e..eb803c05e 100644 --- a/l10n/nl.js +++ b/l10n/nl.js @@ -2038,10 +2038,21 @@ OC.L10N.register( "{n} open action items": "{n} openstaande actiepunten", "{responded} of {invited} responded": "{responded} van {invited} gereageerd", "{states} states, {transitions} transitions": "{states} statussen, {transitions} overgangen", + "Source app": "Bronapplicatie", + "External reference": "Externe referentie", "Which kind of organisation is this for?": "Voor wat voor organisatie is dit?", "Pick the organisation this app runs for and you get a worked example of it: bodies, meetings, decisions and templates that fit. Installing the app plants nothing on its own, so this is the only step that adds data. Choose \"None\" on a production install.": "Kies de organisatie waarvoor deze app draait en je krijgt een uitgewerkt voorbeeld: organen, vergaderingen, besluiten en sjablonen die daarbij passen. De app zet zelf niets klaar, dus dit is de enige stap die gegevens toevoegt. Kies \"Geen\" op een productieomgeving.", "Load the example data": "Laad de voorbeeldgegevens", - "Loads the set you picked. The data is obviously sample data, it is safe to run more than once, and you can delete it afterwards.": "Laadt de set die je koos. De gegevens zijn herkenbaar voorbeeldgegevens, je kunt dit meer dan een keer uitvoeren en je kunt ze daarna verwijderen." + "Loads the set you picked. The data is obviously sample data, it is safe to run more than once, and you can delete it afterwards.": "Laadt de set die je koos. De gegevens zijn herkenbaar voorbeeldgegevens, je kunt dit meer dan een keer uitvoeren en je kunt ze daarna verwijderen.", + "consultationType=tender: the winning party recorded when the award decision is made (status=awarded). Decidiq owns publish/manage/award only; authoring is procest and bidding is pipelinq.": "consultationType=tender: de winnende partij, vastgelegd zodra het gunningsbesluit is genomen (status=awarded). Decidiq beheert alleen publiceren, beheren en gunnen; het opstellen gebeurt in procest en het inschrijven in pipelinq.", + "schema.org annotation matching the ORI type (ChooseAction / Event / CreativeWork).": "schema.org-annotatie die hoort bij het ORI-type (ChooseAction / Event / CreativeWork).", + "consultationType=tender: public tender reference/notice number.": "consultationType=tender: het openbare aanbestedings- of publicatienummer.", + "Association or VvE": "Vereniging of VvE", + "Company board": "Raad van bestuur", + "Every schema, generated values": "Elk schema, gegenereerde waarden", + "Municipality": "Gemeente", + "None, I will set this up myself": "Geen, ik richt dit zelf in", + "Works council": "Ondernemingsraad" }, "nplurals=2; plural=(n != 1);" ) diff --git a/l10n/nl.json b/l10n/nl.json index 235bc38bf..c28f11d4d 100644 --- a/l10n/nl.json +++ b/l10n/nl.json @@ -2037,10 +2037,21 @@ "{n} open action items": "{n} openstaande actiepunten", "{responded} of {invited} responded": "{responded} van {invited} gereageerd", "{states} states, {transitions} transitions": "{states} statussen, {transitions} overgangen", + "Source app": "Bronapplicatie", + "External reference": "Externe referentie", "Which kind of organisation is this for?": "Voor wat voor organisatie is dit?", "Pick the organisation this app runs for and you get a worked example of it: bodies, meetings, decisions and templates that fit. Installing the app plants nothing on its own, so this is the only step that adds data. Choose \"None\" on a production install.": "Kies de organisatie waarvoor deze app draait en je krijgt een uitgewerkt voorbeeld: organen, vergaderingen, besluiten en sjablonen die daarbij passen. De app zet zelf niets klaar, dus dit is de enige stap die gegevens toevoegt. Kies \"Geen\" op een productieomgeving.", "Load the example data": "Laad de voorbeeldgegevens", - "Loads the set you picked. The data is obviously sample data, it is safe to run more than once, and you can delete it afterwards.": "Laadt de set die je koos. De gegevens zijn herkenbaar voorbeeldgegevens, je kunt dit meer dan een keer uitvoeren en je kunt ze daarna verwijderen." + "Loads the set you picked. The data is obviously sample data, it is safe to run more than once, and you can delete it afterwards.": "Laadt de set die je koos. De gegevens zijn herkenbaar voorbeeldgegevens, je kunt dit meer dan een keer uitvoeren en je kunt ze daarna verwijderen.", + "consultationType=tender: the winning party recorded when the award decision is made (status=awarded). Decidiq owns publish/manage/award only; authoring is procest and bidding is pipelinq.": "consultationType=tender: de winnende partij, vastgelegd zodra het gunningsbesluit is genomen (status=awarded). Decidiq beheert alleen publiceren, beheren en gunnen; het opstellen gebeurt in procest en het inschrijven in pipelinq.", + "schema.org annotation matching the ORI type (ChooseAction / Event / CreativeWork).": "schema.org-annotatie die hoort bij het ORI-type (ChooseAction / Event / CreativeWork).", + "consultationType=tender: public tender reference/notice number.": "consultationType=tender: het openbare aanbestedings- of publicatienummer.", + "Association or VvE": "Vereniging of VvE", + "Company board": "Raad van bestuur", + "Every schema, generated values": "Elk schema, gegenereerde waarden", + "Municipality": "Gemeente", + "None, I will set this up myself": "Geen, ik richt dit zelf in", + "Works council": "Ondernemingsraad" }, "plurals": null, "pluralForm": "nplurals=2; plural=(n != 1);" diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 155b2288b..167739a51 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -24,6 +24,7 @@ namespace OCA\Decidiq\AppInfo; use OCA\Decidiq\AppInfo\Registrar\AppHostRegistrar; +use OCA\Decidiq\AppInfo\Registrar\CrossAppEventRegistrar; use OCA\Decidiq\AppInfo\Registrar\DomainServiceRegistrar; use OCA\Decidiq\AppInfo\Registrar\IntegrationLeafRegistrar; use OCA\Decidiq\AppInfo\Registrar\ObjectListenerRegistrar; @@ -46,7 +47,8 @@ * than accumulating here: * * - {@see AppHostRegistrar} AppHost boilerplate adoption (ADR-040 / ADR-022). - * - {@see DomainServiceRegistrar} decision events, MCP tools, eIDAS, translation. + * - {@see CrossAppEventRegistrar} inbound cross-app command listeners (ADR-041). + * - {@see DomainServiceRegistrar} MCP tools, eIDAS, translation. * - {@see PlatformIntegrationRegistrar} search, object-write guards, dashboard widget. * - {@see IntegrationLeafRegistrar} server-side half of the OR integration leaves (ADR-066). * - {@see ObjectListenerRegistrar} boot()-time filtered object-lifecycle subscriptions. @@ -140,6 +142,7 @@ public function register(IRegistrationContext $context): void { // them. // @spec openspec/changes/migrate-comments-to-talk-leaf/tasks.md#task-2.1. // @spec openspec/specs/user-settings/spec.md + (new CrossAppEventRegistrar())->register(context: $context); (new DomainServiceRegistrar())->register(context: $context); // Board portal Phase 2 services (audit log, conflict of interest, diff --git a/lib/AppInfo/Registrar/CrossAppEventRegistrar.php b/lib/AppInfo/Registrar/CrossAppEventRegistrar.php new file mode 100644 index 000000000..7ca3e3ba9 --- /dev/null +++ b/lib/AppInfo/Registrar/CrossAppEventRegistrar.php @@ -0,0 +1,81 @@ + + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * @link https://conduction.nl + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace OCA\Decidiq\AppInfo\Registrar; + +use OCA\Decidiq\Event\DecisionRequestedEvent; +use OCA\Decidiq\Event\GovernanceBodyRequestedEvent; +use OCA\Decidiq\Listener\DecisionRequestedListener; +use OCA\Decidiq\Listener\GovernanceBodyRequestedListener; +use OCP\AppFramework\Bootstrap\IRegistrationContext; + +/** + * Registers every inbound cross-app command listener. + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ +class CrossAppEventRegistrar { + + /** + * The command contract, as event class => listener class. + * + * A map rather than four call sites, so adding a command is one line and + * the whole inbound surface reads as one list. + * + * @var array + */ + private const COMMANDS = [ + // Raise a governance Decision for a consumer's object, and conclude it + // back through DecisionConcludedEvent. + DecisionRequestedEvent::class => DecisionRequestedListener::class, + + // Hold a governance body — a committee, a board — with its roster. + GovernanceBodyRequestedEvent::class => GovernanceBodyRequestedListener::class, + ]; + + /** + * Register every command listener. + * + * @param IRegistrationContext $context The registration context. + * + * @return void + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function register(IRegistrationContext $context): void { + foreach (self::COMMANDS as $event => $listener) { + $context->registerEventListener(event: $event, listener: $listener); + } + + }//end register() + +}//end class diff --git a/lib/AppInfo/Registrar/DomainServiceRegistrar.php b/lib/AppInfo/Registrar/DomainServiceRegistrar.php index 94c346b97..8553f57af 100644 --- a/lib/AppInfo/Registrar/DomainServiceRegistrar.php +++ b/lib/AppInfo/Registrar/DomainServiceRegistrar.php @@ -32,8 +32,6 @@ namespace OCA\Decidiq\AppInfo\Registrar; -use OCA\Decidiq\Event\DecisionRequestedEvent; -use OCA\Decidiq\Listener\DecisionRequestedListener; use OCA\Decidiq\Mcp\DecidiqToolProvider; use OCA\Decidiq\Service\EIDASSignatureService; use OCA\Decidiq\Service\IEIDASSignatureService; @@ -73,35 +71,12 @@ class DomainServiceRegistrar { * @spec openspec/specs/mcp-tools/spec.md */ public function register(IRegistrationContext $context): void { - $this->registerDecisionEvents(context: $context); $this->registerMcpToolProvider(context: $context); $this->registerEidasBindings(context: $context); $this->registerTranslationAdapter(context: $context); }//end register() - /** - * The event contract for delegated decisions. - * - * Consumer apps dispatch DecisionRequestedEvent (handled here -> - * createDecision) and listen for DecisionConcludedEvent (emitted from - * DecisionLifecycleService). In-process replacement for the broken - * IntegrationService::getLeaf path. - * - * @param IRegistrationContext $context The registration context - * - * @return void - * - * @spec openspec/changes/decidesk-decision-events/specs/decidesk-decision-events/spec.md - */ - private function registerDecisionEvents(IRegistrationContext $context): void { - $context->registerEventListener( - event: DecisionRequestedEvent::class, - listener: DecisionRequestedListener::class - ); - - }//end registerDecisionEvents() - /** * Register DecidiqToolProvider as the MCP tool provider for the AI Chat Companion. * diff --git a/lib/Event/GovernanceBodyCreatedEvent.php b/lib/Event/GovernanceBodyCreatedEvent.php new file mode 100644 index 000000000..d6e910b3e --- /dev/null +++ b/lib/Event/GovernanceBodyCreatedEvent.php @@ -0,0 +1,121 @@ + + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * @link https://conduction.nl + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace OCA\Decidiq\Event; + +use OCP\EventDispatcher\Event; + +/** + * Conclusion event for a cross-app governance-body command. + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ +class GovernanceBodyCreatedEvent extends Event { + + /** + * Construct the conclusion event. + * + * @param string $governanceBodyId The id Decidiq created or matched + * @param string $sourceApp App id of the producer the command came from + * @param string $externalReference The producer's own id for the originating record + * @param boolean $created True when this command minted the body, false when one matched + * @param string $correlationId Correlation id echoed from the request + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function __construct( + private readonly string $governanceBodyId, + private readonly string $sourceApp, + private readonly string $externalReference, + private readonly bool $created, + private readonly string $correlationId = '', + ) { + parent::__construct(); + + }//end __construct() + + /** + * Get the resolved GovernanceBody id. + * + * @return string The id + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function getGovernanceBodyId(): string { + return $this->governanceBodyId; + + }//end getGovernanceBodyId() + + /** + * Get the producing app id. + * + * @return string The app id + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function getSourceApp(): string { + return $this->sourceApp; + + }//end getSourceApp() + + /** + * Get the producer's own reference. + * + * @return string The external reference + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function getExternalReference(): string { + return $this->externalReference; + + }//end getExternalReference() + + /** + * Whether the body was newly created rather than matched. + * + * @return boolean The created flag + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function isCreated(): bool { + return $this->created; + + }//end isCreated() + + /** + * Get the correlation id echoed from the request. + * + * @return string The correlation id + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function getCorrelationId(): string { + return $this->correlationId; + + }//end getCorrelationId() + +}//end class diff --git a/lib/Event/GovernanceBodyRequestedEvent.php b/lib/Event/GovernanceBodyRequestedEvent.php new file mode 100644 index 000000000..f4ea9ad31 --- /dev/null +++ b/lib/Event/GovernanceBodyRequestedEvent.php @@ -0,0 +1,306 @@ + + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * @link https://conduction.nl + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace OCA\Decidiq\Event; + +use OCP\EventDispatcher\Event; + +/** + * Cross-app command event: a consumer app asks Decidiq to raise a GovernanceBody. + * + * All request fields are immutable (constructor-injected getters). Nextcloud + * typed dispatch is synchronous, so the result slots (governanceBodyId, created, + * handled) are written by Decidiq's listener and read by the producer right + * after dispatch — the same request/response-over-the-bus pattern + * DecisionRequestedEvent uses. + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ +class GovernanceBodyRequestedEvent extends Event { + + /** + * The id of the GovernanceBody Decidiq created or matched (result slot). + * + * @var string|null + */ + private ?string $governanceBodyId = null; + + /** + * Whether the body was newly created (false when an existing one matched). + * + * @var boolean + */ + private bool $created = false; + + /** + * Whether Decidiq's listener handled this command (result slot). + * + * @var boolean + */ + private bool $handled = false; + + /** + * Construct the command event. + * + * @param string $sourceApp App id of the producer (e.g. dossiq) + * @param string $externalReference The producer's own id for the originating record + * @param string $name Body name + * @param string $bodyType GovernanceBody bodyType (e.g. advisory-body) + * @param string $domain Governance domain preset + * @param boolean $active Whether the body may be assigned new work. Stated, never defaulted + * @param array $attributes Further body fields (quorum, jurisdiction, statutoryBasis, termStart, termEnd, parentBody) + * @param array> $members Roster entries of {uid, role, external, label} + * @param string $actorId Nextcloud UID on whose behalf the command runs + * @param string $correlationId Correlation id echoed on GovernanceBodyCreatedEvent + * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) This parameter list is a + * PUBLISHED CROSS-APP CONTRACT, not an internal signature. A consumer app + * constructs the event POSITIONALLY through a class-string so it stays + * installable without Decidiq — the same constraint DecisionRequestedEvent + * documents. Collapsing these into an array would move the contract from the + * signature into an undocumented key set. + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function __construct( + private readonly string $sourceApp, + private readonly string $externalReference, + private readonly string $name, + private readonly string $bodyType, + private readonly string $domain, + private readonly bool $active, + private readonly array $attributes = [], + private readonly array $members = [], + private readonly string $actorId = '', + private readonly string $correlationId = '', + ) { + parent::__construct(); + + }//end __construct() + + /** + * Get the producing app id. + * + * @return string The app id + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function getSourceApp(): string { + return $this->sourceApp; + + }//end getSourceApp() + + /** + * Get the producer's own reference for the originating record. + * + * @return string The external reference + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function getExternalReference(): string { + return $this->externalReference; + + }//end getExternalReference() + + /** + * Get the body name. + * + * @return string The name + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function getName(): string { + return $this->name; + + }//end getName() + + /** + * Get the body type. + * + * @return string The bodyType + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function getBodyType(): string { + return $this->bodyType; + + }//end getBodyType() + + /** + * Get the governance domain. + * + * @return string The domain + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function getDomain(): string { + return $this->domain; + + }//end getDomain() + + /** + * Whether the body may be assigned new work. + * + * @return boolean The active flag + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function isActive(): bool { + return $this->active; + + }//end isActive() + + /** + * Get the further body fields. + * + * @return array The attribute map + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function getAttributes(): array { + return $this->attributes; + + }//end getAttributes() + + /** + * Get the roster entries. + * + * @return array> The members + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function getMembers(): array { + return $this->members; + + }//end getMembers() + + /** + * Get the acting Nextcloud UID. + * + * @return string The actor id + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function getActorId(): string { + return $this->actorId; + + }//end getActorId() + + /** + * Get the correlation id. + * + * @return string The correlation id + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function getCorrelationId(): string { + return $this->correlationId; + + }//end getCorrelationId() + + /** + * Get the resolved GovernanceBody id. + * + * @return string The id, or an empty string when unhandled + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function getGovernanceBodyId(): string { + return ($this->governanceBodyId ?? ''); + + }//end getGovernanceBodyId() + + /** + * Record the resolved GovernanceBody id (result slot). + * + * @param string $governanceBodyId The id Decidiq created or matched + * + * @return void + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function setGovernanceBodyId(string $governanceBodyId): void { + $this->governanceBodyId = $governanceBodyId; + + }//end setGovernanceBodyId() + + /** + * Whether the body was newly created rather than matched. + * + * @return boolean The created flag + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function isCreated(): bool { + return $this->created; + + }//end isCreated() + + /** + * Record whether the body was newly created (result slot). + * + * @param boolean $created True when this command minted the body + * + * @return void + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function setCreated(bool $created): void { + $this->created = $created; + + }//end setCreated() + + /** + * Whether Decidiq handled the command. + * + * @return boolean The handled flag + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function isHandled(): bool { + return $this->handled; + + }//end isHandled() + + /** + * Record that Decidiq handled the command (result slot). + * + * @param boolean $handled True when the command was applied + * + * @return void + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function setHandled(bool $handled): void { + $this->handled = $handled; + + }//end setHandled() + +}//end class diff --git a/lib/Listener/GovernanceBodyRequestedListener.php b/lib/Listener/GovernanceBodyRequestedListener.php new file mode 100644 index 000000000..911ee672b --- /dev/null +++ b/lib/Listener/GovernanceBodyRequestedListener.php @@ -0,0 +1,131 @@ + + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * @link https://conduction.nl + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace OCA\Decidiq\Listener; + +use OCA\Decidiq\Event\GovernanceBodyCreatedEvent; +use OCA\Decidiq\Event\GovernanceBodyRequestedEvent; +use OCA\Decidiq\Service\GovernanceBodyCommandService; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\EventDispatcher\IEventListener; +use Psr\Log\LoggerInterface; +use Throwable; + +/** + * Handles GovernanceBodyRequestedEvent by delegating to the command service. + * + * @implements IEventListener + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ +class GovernanceBodyRequestedListener implements IEventListener { + + /** + * Constructor. + * + * @param GovernanceBodyCommandService $commandService The idempotent upsert engine. + * @param IEventDispatcher $dispatcher Dispatcher for the conclusion event. + * @param LoggerInterface $logger Logger. + */ + public function __construct( + private readonly GovernanceBodyCommandService $commandService, + private readonly IEventDispatcher $dispatcher, + private readonly LoggerInterface $logger, + ) { + }//end __construct() + + /** + * Handle a GovernanceBodyRequestedEvent. + * + * @param Event $event The dispatched event. + * + * @return void + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function handle(Event $event): void { + if ($event instanceof GovernanceBodyRequestedEvent === false) { + return; + } + + try { + $result = $this->commandService->upsert( + sourceApp: $event->getSourceApp(), + externalReference: $event->getExternalReference(), + body: ($event->getAttributes() + [ + 'name' => $event->getName(), + 'bodyType' => $event->getBodyType(), + 'domain' => $event->getDomain(), + 'active' => $event->isActive(), + ]), + members: $event->getMembers(), + ); + } catch (Throwable $e) { + // The producer sees isHandled() === false and decides what to do. + // Nothing is rethrown: an exception out of handle() aborts the whole + // dispatch, so an unrelated listener on the same event would stop + // running because this one failed. + $this->logger->error( + 'Decidiq: GovernanceBodyRequestedEvent not handled', + [ + 'sourceApp' => $event->getSourceApp(), + 'externalReference' => $event->getExternalReference(), + 'exception' => $e, + ] + ); + return; + }//end try + + $event->setGovernanceBodyId($result['id']); + $event->setCreated($result['created']); + $event->setHandled(true); + + $this->logger->info( + 'Decidiq: handled GovernanceBodyRequestedEvent', + [ + 'sourceApp' => $event->getSourceApp(), + 'externalReference' => $event->getExternalReference(), + 'governanceBodyId' => $result['id'], + 'created' => $result['created'], + ] + ); + + $this->dispatcher->dispatchTyped( + new GovernanceBodyCreatedEvent( + governanceBodyId: $result['id'], + sourceApp: $event->getSourceApp(), + externalReference: $event->getExternalReference(), + created: $result['created'], + correlationId: $event->getCorrelationId(), + ) + ); + + }//end handle() + +}//end class diff --git a/lib/Service/ApprovalRouteService.php b/lib/Service/ApprovalRouteService.php index 632f9d4f2..9f088abd9 100644 --- a/lib/Service/ApprovalRouteService.php +++ b/lib/Service/ApprovalRouteService.php @@ -66,10 +66,10 @@ class ApprovalRouteService { /** * Constructor. * - * @param ApprovalRouteStore $store Reads and writes the objects a route is made of. + * @param RegisterObjectStore $store Reads and writes the objects a route is made of. */ public function __construct( - private readonly ApprovalRouteStore $store, + private readonly RegisterObjectStore $store, ) { }//end __construct() diff --git a/lib/Service/GovernanceBodyCommandService.php b/lib/Service/GovernanceBodyCommandService.php new file mode 100644 index 000000000..c1195f81e --- /dev/null +++ b/lib/Service/GovernanceBodyCommandService.php @@ -0,0 +1,415 @@ + + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * SPDX-License-Identifier: EUPL-1.2 + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * + * @version GIT: + * + * @link https://conduction.nl + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + +declare(strict_types=1); + +namespace OCA\Decidiq\Service; + +use RuntimeException; + +/** + * Idempotent upsert of a GovernanceBody plus its Person/Membership roster. + * + * Every write in here is preceded by a resolve. That is the whole design: a + * migration in the producing app is re-runnable by construction, and a partial + * run is completed by the next one rather than duplicated by it. + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ +class GovernanceBodyCommandService { + + /** + * Schema slug of the body. + */ + private const SCHEMA_BODY = 'governance-body'; + + /** + * Schema slug of a natural person. + */ + private const SCHEMA_PERSON = 'person'; + + /** + * Schema slug of a person's seat on a body. + */ + private const SCHEMA_MEMBERSHIP = 'membership'; + + /** + * Body fields a command may set beyond the five it states explicitly. + * + * A closed list, not a passthrough: an open merge would let a producing app + * write `sourceApp` or `externalReference` itself and break the key this + * service resolves on. + * + * @var list + */ + private const ALLOWED_ATTRIBUTES = [ + 'quorum', + 'quorumRule', + 'jurisdiction', + 'statutoryBasis', + 'votingDefault', + 'termStart', + 'termEnd', + 'parentBody', + 'workflowTemplate', + ]; + + /** + * Membership roles this seam accepts, matching Membership.role. + * + * @var list + */ + private const ALLOWED_ROLES = [ + 'chair', + 'vice-chair', + 'secretary', + 'treasurer', + 'member', + 'observer', + ]; + + /** + * Constructor. + * + * @param RegisterObjectStore $store Reads and writes decidiq's register objects. + */ + public function __construct( + private readonly RegisterObjectStore $store, + ) { + }//end __construct() + + /** + * Raise or update a governance body and its roster. + * + * @param string $sourceApp App id of the producer. + * @param string $externalReference The producer's own id for the originating record. + * @param array $body Body fields; MUST carry name, bodyType, domain and active. + * @param array> $members Roster entries of {uid, role, external, label}. + * + * @return array{id: string, created: bool} The resolved id and whether it was minted here. + * + * @throws RuntimeException When the command is incomplete or a write fails. + * + * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + */ + public function upsert( + string $sourceApp, + string $externalReference, + array $body, + array $members = [], + ): array { + if ($sourceApp === '' || $externalReference === '') { + throw new RuntimeException( + 'A governance-body command needs both sourceApp and externalReference: they are the key a re-run resolves on' + ); + } + + $payload = $this->buildBodyPayload( + sourceApp: $sourceApp, + externalReference: $externalReference, + body: $body, + ); + + $existing = $this->findBody(sourceApp: $sourceApp, externalReference: $externalReference); + $created = ($existing === null); + + // The body is saved and its id read BEFORE the first membership write. + // A membership written against an unsaved body points at nothing, and a + // crash between the two then leaves orphans instead of a body the next + // run can complete (REQ-GBE-004). + $stored = $this->store->save( + schema: self::SCHEMA_BODY, + object: $payload, + uuid: $this->idOf(row: ($existing ?? [])), + ); + + $bodyId = $this->idOf(row: $stored); + if ($bodyId === null) { + throw new RuntimeException('OpenRegister returned a governance body with no id'); + } + + $this->syncRoster(bodyId: $bodyId, members: $members); + + return [ + 'id' => $bodyId, + 'created' => $created, + ]; + + }//end upsert() + + /** + * Build the body object to store. + * + * @param string $sourceApp App id of the producer. + * @param string $externalReference The producer's own reference. + * @param array $body The commanded body fields. + * + * @return array The payload. + * + * @throws RuntimeException When a required field is missing. + */ + private function buildBodyPayload(string $sourceApp, string $externalReference, array $body): array { + foreach (['name', 'bodyType', 'domain'] as $required) { + if (($body[$required] ?? '') === '') { + throw new RuntimeException('A governance-body command needs a ' . $required); + } + } + + // `active` decides whether the body may be assigned new work, and the + // consuming app throws on it. Defaulting an absent value to true would + // route objections to a disbanded committee and nothing would error, so + // an omitted `active` is refused instead (REQ-GBE-005). + if (array_key_exists('active', $body) === false || is_bool($body['active']) === false) { + throw new RuntimeException( + 'A governance-body command must state `active` as a boolean: it is never defaulted' + ); + } + + $payload = [ + 'name' => (string)$body['name'], + 'bodyType' => (string)$body['bodyType'], + 'domain' => (string)$body['domain'], + 'active' => $body['active'], + 'sourceApp' => $sourceApp, + 'externalReference' => $externalReference, + ]; + + foreach (self::ALLOWED_ATTRIBUTES as $key) { + if (array_key_exists($key, $body) === true && $body[$key] !== null && $body[$key] !== '') { + $payload[$key] = $body[$key]; + } + } + + return $payload; + + }//end buildBodyPayload() + + /** + * Resolve an existing body by its provenance pair. + * + * @param string $sourceApp App id of the producer. + * @param string $externalReference The producer's own reference. + * + * @return array|null The row, or null when none matches. + */ + private function findBody(string $sourceApp, string $externalReference): ?array { + $rows = $this->store->findAll( + schema: self::SCHEMA_BODY, + filters: [ + 'sourceApp' => $sourceApp, + 'externalReference' => $externalReference, + ], + ); + + // The filter is re-checked in PHP rather than trusted. A filter key the + // store does not recognise is dropped rather than refused, and a dropped + // filter returns EVERY body — which would make this method match the + // first unrelated row and silently overwrite it. + foreach ($rows as $row) { + $matchesApp = ((string)($row['sourceApp'] ?? '') === $sourceApp); + $matchesRef = ((string)($row['externalReference'] ?? '') === $externalReference); + if ($matchesApp === true && $matchesRef === true) { + return $row; + } + } + + return null; + + }//end findBody() + + /** + * Create or update one seat per roster entry. + * + * @param string $bodyId The stored body's id. + * @param array> $members The roster. + * + * @return void + * + * @throws RuntimeException When an entry is unusable. + */ + private function syncRoster(string $bodyId, array $members): void { + foreach ($members as $member) { + $uid = trim((string)($member['uid'] ?? '')); + if ($uid === '') { + throw new RuntimeException('A roster entry needs a uid'); + } + + $role = (string)($member['role'] ?? 'member'); + if (in_array($role, self::ALLOWED_ROLES, true) === false) { + throw new RuntimeException('Unknown membership role: ' . $role); + } + + $personId = $this->resolvePerson(uid: $uid, member: $member); + $this->upsertMembership( + bodyId: $bodyId, + personId: $personId, + role: $role, + member: $member, + ); + } + + }//end syncRoster() + + /** + * Find the Person for a Nextcloud uid, creating one only when absent. + * + * @param string $uid The Nextcloud user id. + * @param array $member The roster entry. + * + * @return string The person's id. + * + * @throws RuntimeException When the person cannot be stored. + */ + private function resolvePerson(string $uid, array $member): string { + $rows = $this->store->findAll( + schema: self::SCHEMA_PERSON, + filters: ['nextcloudUserId' => $uid], + ); + + foreach ($rows as $row) { + if ((string)($row['nextcloudUserId'] ?? '') !== $uid) { + continue; + } + + $id = $this->idOf(row: $row); + if ($id !== null) { + return $id; + } + } + + $name = trim((string)($member['name'] ?? '')); + if ($name === '') { + $name = $uid; + } + + $stored = $this->store->save( + schema: self::SCHEMA_PERSON, + object: [ + 'name' => $name, + 'nextcloudUserId' => $uid, + ], + ); + + $id = $this->idOf(row: $stored); + if ($id === null) { + throw new RuntimeException('OpenRegister returned a person with no id'); + } + + return $id; + + }//end resolvePerson() + + /** + * Create or update the one seat this person holds on this body. + * + * @param string $bodyId The body's id. + * @param string $personId The person's id. + * @param string $role The membership role. + * @param array $member The roster entry. + * + * @return void + */ + private function upsertMembership(string $bodyId, string $personId, string $role, array $member): void { + $rows = $this->store->findAll( + schema: self::SCHEMA_MEMBERSHIP, + filters: [ + 'governanceBody' => $bodyId, + 'person' => $personId, + ], + ); + + $existingId = null; + foreach ($rows as $row) { + $sameBody = ($this->refOf(value: ($row['governanceBody'] ?? null)) === $bodyId); + $samePerson = ($this->refOf(value: ($row['person'] ?? null)) === $personId); + if ($sameBody === true && $samePerson === true) { + $existingId = $this->idOf(row: $row); + break; + } + } + + $object = [ + 'governanceBody' => $bodyId, + 'person' => $personId, + 'role' => $role, + // Awb 7:13(2): the secretary sits from outside the administrative + // organ. The producer states it; an absent value reads as false + // because "not declared external" is the ordinary case. + 'external' => (bool)($member['external'] ?? false), + ]; + + $label = trim((string)($member['label'] ?? '')); + if ($label !== '') { + $object['label'] = $label; + } + + $this->store->save( + schema: self::SCHEMA_MEMBERSHIP, + object: $object, + uuid: $existingId, + ); + + }//end upsertMembership() + + /** + * Read an object's id out of either shape OpenRegister returns. + * + * @param array $row The row. + * + * @return string|null The id, or null when absent. + */ + private function idOf(array $row): ?string { + $id = (string)($row['id'] ?? ($row['@self']['id'] ?? '')); + if ($id === '') { + return null; + } + + return $id; + + }//end idOf() + + /** + * Reduce a relation value to the id it points at. + * + * OpenRegister returns a relation as a bare uuid string, or as the expanded + * object when the read inlined it. Comparing the raw value would miss the + * expanded form and mint a second membership on every re-run. + * + * @param mixed $value The relation value. + * + * @return string The id, or an empty string. + */ + private function refOf(mixed $value): string { + if (is_array($value) === true) { + return (string)($value['id'] ?? ($value['@self']['id'] ?? '')); + } + + return (string)$value; + + }//end refOf() + +}//end class diff --git a/lib/Service/ApprovalRouteStore.php b/lib/Service/RegisterObjectStore.php similarity index 84% rename from lib/Service/ApprovalRouteStore.php rename to lib/Service/RegisterObjectStore.php index bd3edddff..446c35658 100644 --- a/lib/Service/ApprovalRouteStore.php +++ b/lib/Service/RegisterObjectStore.php @@ -1,12 +1,16 @@ getUser()` is null, which is exactly the state a background + migration runs in. + +The pattern already exists in this app and is the one being copied: +`DecisionRequestedEvent` → `DecisionRequestedListener` → +`DecisionIntegrationService::createDecision()`, with the resolved id written +back onto the event instance and `DecisionConcludedEvent` carrying the +correlation home. + +## Affected Projects + +- [x] Project: `decidiq` — this change. Two events, a command service, a + listener, an idempotency key on `GovernanceBody`. +- [ ] Project: `dossiq` — the consumer. `migrate-committees-to-decidiq` + unblocks on this and is not part of it. + +## Scope + +### In Scope + +1. **`GovernanceBody` gains `sourceApp` and `externalReference`**, additively, + in a register.d fragment. This is the idempotency key and the audit trail of + where a body came from. `Decision` already carries exactly this pair for + exactly this reason; a governance body raised by another app needs it for + the same one. +2. **`GovernanceBodyRequestedEvent`** — the inbound command. Body fields plus a + `members[]` roster of `{uid, role, external}`, a `sourceApp`, an + `externalReference`, a `correlationId`, and an `actorId`. Result slots for + `governanceBodyId`, `created` and `handled`, written by the listener and read + by the producer right after dispatch. +3. **`GovernanceBodyCommandService`** — the engine: + - `upsert()` resolves an existing body by `(sourceApp, externalReference)` + BEFORE writing anything, so a re-run updates rather than mints a second. + - The roster fans out to `Person` + `Membership`. A `Person` is resolved by + `nextcloudUserId` (which `67-model-debt-cleanup` already added) and created + only when absent. + - A `Membership` is resolved by `(person, governanceBody)` so a re-run + updates the role rather than adding a second seat. + - **The body is written before the memberships**, so a crash between them + leaves a body with a partial roster that the next run completes, rather + than orphan memberships pointing at nothing. +4. **`GovernanceBodyRequestedListener`** — maps the event onto the service, + writes the result slots, dispatches `GovernanceBodyCreatedEvent`, and never + lets an exception escape into the dispatcher. +5. **Registration** in `DomainServiceRegistrar`, beside `registerDecisionEvents`. + +### Out of Scope + +- **Any dossiq change.** The migration, the read path and the retirement of + dossiq's local schema are dossiq's. +- **A UI.** Bodies raised this way are ordinary `GovernanceBody` rows and appear + in the existing list and detail pages with no new surface. +- **Deleting a body.** The seam creates and updates; retirement is `active: + false` through the normal surface. + +## Risks + +- 🔴 **A fan-out migration is not idempotent by default.** This is the risk the + consuming proposal names, and it is answered here rather than there: + resolution by `(sourceApp, externalReference)` for the body and by + `nextcloudUserId` for the person are what make a re-run safe. Both are + asserted by tests that call the seam TWICE and count rows, because a test + that calls it once cannot tell an idempotent write from a duplicating one. +- 🔴 **`active` is load-bearing on the consumer side.** dossiq's + `AdvisoryCommitteeService` throws "Committee is archived" on it. The event + carries it explicitly and the service never defaults it silently: an absent + `active` is an error, not a `true`. +- ⚠️ **A `Person` matched by `nextcloudUserId` may be a different human with a + recycled uid.** Accepted: NC uids are not reissued in practice, and the + alternative (matching on name) is worse. +- ⚠️ **The listener runs synchronously inside the producer's request.** A slow + fan-out is the producer's latency. Bounded by the roster size, which for an + Awb 7:13 committee is single digits. + +## Status + +Ready. No dependency outside this repo. diff --git a/openspec/changes/governance-body-events/specs/governance-body-events/spec.md b/openspec/changes/governance-body-events/specs/governance-body-events/spec.md new file mode 100644 index 000000000..05c028e5b --- /dev/null +++ b/openspec/changes/governance-body-events/specs/governance-body-events/spec.md @@ -0,0 +1,117 @@ +# governance-body-events Specification + +## Purpose + +An in-process command seam that lets another installed fleet app ask decidiq to +raise a `GovernanceBody` with its roster, and read back the id decidiq gave it. +Per ADR-041 a cross-app command travels as a typed event, not as REST. + +## Requirements + +### Requirement: REQ-GBE-001 A governance body carries where it came from + +`GovernanceBody` SHALL carry `sourceApp` and `externalReference`. Together they +identify the originating record in the producing app, and they are the key the +seam resolves on so a repeated command updates one body rather than minting a +second. + +#### Scenario: The pair is additive + +- **GIVEN** the register fragment +- **WHEN** the register imports +- **THEN** `GovernanceBody` has `sourceApp` and `externalReference` +- **AND** its `required` list is unchanged, so every stored body stays valid +- **AND** a body created through the existing UI leaves both empty + +### Requirement: REQ-GBE-002 The seam is a typed event, dispatched and answered in process + +Decidiq SHALL register a listener for `GovernanceBodyRequestedEvent`. The +listener SHALL write the resolved id, the created flag and the handled flag onto +the dispatched instance, so a producer reads the result immediately after +dispatch. + +#### Scenario: A request raises a body and answers with its id + +- **GIVEN** an installed decidiq and no body for `(dossiq, cmte-1)` +- **WHEN** a producer dispatches `GovernanceBodyRequestedEvent` for it +- **THEN** a `GovernanceBody` exists with the mapped fields +- **AND** the event reports `handled = true`, `created = true`, and a non-empty + `governanceBodyId` + +#### Scenario: A failure leaves the event unhandled and throws nothing + +- **GIVEN** OpenRegister rejects the write +- **WHEN** the event is dispatched +- **THEN** `handled` is false and `governanceBodyId` is empty +- **AND** no exception escapes the dispatcher, so an unrelated listener still runs + +### Requirement: REQ-GBE-003 A repeated command updates, it does not duplicate + +The service SHALL resolve an existing body by `(sourceApp, externalReference)` +before writing. A second command carrying the same pair SHALL update that body +and SHALL NOT create another. The same rule applies to each roster member: a +`Person` resolves by `nextcloudUserId` and a `Membership` by its +`(person, governanceBody)` pair. + +#### Scenario: Dispatching the same command twice creates one body + +- **GIVEN** a command for `(dossiq, cmte-1)` that has already been handled +- **WHEN** the identical command is dispatched again +- **THEN** exactly one `GovernanceBody` exists for that pair +- **AND** the event reports `created = false` with the same id as the first run + +#### Scenario: Dispatching the same command twice creates one seat per member + +- **GIVEN** a command whose roster names `alice` as chair, already handled +- **WHEN** the identical command is dispatched again +- **THEN** exactly one `Person` exists with `nextcloudUserId = alice` +- **AND** exactly one `Membership` links that person to that body + +#### Scenario: A changed role updates the seat rather than adding one + +- **GIVEN** a handled command naming `alice` as `member` +- **WHEN** a command with the same `externalReference` names `alice` as `chair` +- **THEN** her single membership reads `chair` + +### Requirement: REQ-GBE-004 The body is written before its roster + +The service SHALL persist the `GovernanceBody` and obtain its id BEFORE writing +any `Membership`. A membership SHALL never be written against an unsaved body. + +#### Scenario: A crash mid-fan-out leaves a completable body + +- **GIVEN** a roster of three where the second membership write fails +- **WHEN** the command is dispatched +- **THEN** the body exists with the first membership +- **AND** re-dispatching the command completes the roster without duplicating + the first + +### Requirement: REQ-GBE-005 `active` is never defaulted silently + +`active` decides whether a body may be assigned new work, and the consuming app +throws on it. The service SHALL require the command to state it, and SHALL +refuse a command that omits it rather than assuming `true`. + +#### Scenario: An omitted active is refused + +- **WHEN** a command is dispatched with no `active` +- **THEN** the seam refuses it, no body is written, and `handled` is false + +#### Scenario: An archived committee stays archived across a re-run + +- **GIVEN** a handled command that set `active = false` +- **WHEN** the identical command is dispatched again +- **THEN** the body still reads `active = false` + +### Requirement: REQ-GBE-006 The producer learns the outcome by correlation + +After a successful command the listener SHALL dispatch +`GovernanceBodyCreatedEvent` carrying the `correlationId` from the request, the +resulting `governanceBodyId`, and whether the body was created or matched. + +#### Scenario: The conclusion echoes the correlation + +- **GIVEN** a command carrying `correlationId = abc` +- **WHEN** it is handled +- **THEN** a `GovernanceBodyCreatedEvent` is dispatched with `correlationId = + abc` and the same id the request reports diff --git a/openspec/changes/governance-body-events/tasks.md b/openspec/changes/governance-body-events/tasks.md new file mode 100644 index 000000000..6a1311848 --- /dev/null +++ b/openspec/changes/governance-body-events/tasks.md @@ -0,0 +1,43 @@ +# Tasks: governance-body-events + +## Implementation Tasks + +### Task 1: `sourceApp` + `externalReference` on GovernanceBody +- **spec_ref**: `openspec/changes/governance-body-events/specs/governance-body-events/spec.md#requirement-req-gbe-001-a-governance-body-carries-where-it-came-from` +- **files**: `lib/Settings/register.d/71-governance-body-events.json` +- **acceptance_criteria**: + - GIVEN the fragment WHEN the register imports THEN `GovernanceBody` has both properties and no other schema is touched + - GIVEN `GovernanceBody.required` WHEN compared to before THEN it is unchanged +- [x] Implement +- [x] Test + +### Task 2: The two events +- **spec_ref**: `openspec/changes/governance-body-events/specs/governance-body-events/spec.md#requirement-req-gbe-002-the-seam-is-a-typed-event-dispatched-and-answered-in-process` +- **files**: `lib/Event/GovernanceBodyRequestedEvent.php`, `lib/Event/GovernanceBodyCreatedEvent.php` +- **acceptance_criteria**: + - GIVEN the request event WHEN constructed positionally THEN every field reads back, because a consumer app builds it through a class-string and cannot use named arguments safely + - GIVEN the result slots WHEN unset THEN `isHandled()` is false and `getGovernanceBodyId()` is empty +- [x] Implement +- [x] Test + +### Task 3: GovernanceBodyCommandService — idempotent upsert + roster fan-out +- **spec_ref**: `.../spec.md#requirement-req-gbe-003-a-repeated-command-updates-it-does-not-duplicate` (+ REQ-GBE-004/REQ-GBE-005) +- **files**: `lib/Service/GovernanceBodyCommandService.php` +- **acceptance_criteria**: + - GIVEN a command WHEN dispatched twice THEN one body, one Person per uid, one Membership per person — asserted by COUNTING rows after the second call, not by inspecting the first + - GIVEN a member whose role changes WHEN re-dispatched THEN the existing membership is updated, not supplemented + - GIVEN a roster WHEN written THEN the body is saved and its id read BEFORE the first membership write + - GIVEN a command with no `active` WHEN dispatched THEN it is refused and nothing is written + - GIVEN `active = false` WHEN re-dispatched identically THEN the body stays false +- [x] Implement +- [x] Test + +### Task 4: Listener + registration +- **spec_ref**: `.../spec.md#requirement-req-gbe-006-the-producer-learns-the-outcome-by-correlation` +- **files**: `lib/Listener/GovernanceBodyRequestedListener.php`, `lib/AppInfo/Registrar/DomainServiceRegistrar.php` +- **acceptance_criteria**: + - GIVEN a handled command WHEN it completes THEN `GovernanceBodyCreatedEvent` carries the request's correlationId and the same id + - GIVEN the service throws WHEN the event is dispatched THEN `handled` is false and NO exception escapes handle() + - GIVEN an event of another type WHEN passed to handle() THEN it returns without touching anything +- [x] Implement +- [x] Test diff --git a/tests/Unit/Listener/GovernanceBodyRequestedListenerTest.php b/tests/Unit/Listener/GovernanceBodyRequestedListenerTest.php new file mode 100644 index 000000000..741b2db0a --- /dev/null +++ b/tests/Unit/Listener/GovernanceBodyRequestedListenerTest.php @@ -0,0 +1,205 @@ + + * SPDX-License-Identifier: EUPL-1.2 + * + * @category Test + * @package OCA\Decidiq\Tests\Unit\Listener + * @author Conduction B.V. + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 + * @link https://github.com/ConductionNL/decidiq + */ + +declare(strict_types=1); + +namespace OCA\Decidiq\Tests\Unit\Listener; + +use OCA\Decidiq\Event\GovernanceBodyCreatedEvent; +use OCA\Decidiq\Event\GovernanceBodyRequestedEvent; +use OCA\Decidiq\Listener\GovernanceBodyRequestedListener; +use OCA\Decidiq\Service\GovernanceBodyCommandService; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventDispatcher; +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; +use RuntimeException; + +/** + * Covers the governance-body command listener. + * + * The failure test is the load-bearing one. An exception out of handle() aborts + * the whole typed dispatch, so a listener that rethrows takes down every other + * listener on the same event — and the producer, which reads its answer off the + * event instance, would never reach the line where it checks isHandled(). + */ +class GovernanceBodyRequestedListenerTest extends TestCase { + + /** + * A request event. + * + * @return GovernanceBodyRequestedEvent The event. + */ + private function event(): GovernanceBodyRequestedEvent { + return new GovernanceBodyRequestedEvent( + 'dossiq', + 'cmte-1', + 'Bezwaarcommissie sociaal domein', + 'advisory-body', + 'social_domain', + true, + ['statutoryBasis' => 'Awb 7:13'], + [['uid' => 'alice', 'role' => 'chair']], + 'admin', + 'corr-1', + ); + + }//end event() + + /** + * A handled command writes the result slots and announces the conclusion. + * + * @return void + */ + public function testHandledCommandWritesResultSlotsAndAnnounces(): void { + $service = $this->createMock(GovernanceBodyCommandService::class); + $service->method('upsert')->willReturn(['id' => 'gb-9', 'created' => true]); + + $announced = []; + $dispatcher = $this->createMock(IEventDispatcher::class); + $dispatcher->method('dispatchTyped')->willReturnCallback( + static function (Event $e) use (&$announced): void { + $announced[] = $e; + } + ); + + $event = $this->event(); + $listener = new GovernanceBodyRequestedListener( + $service, + $dispatcher, + $this->createMock(LoggerInterface::class), + ); + $listener->handle($event); + + $this->assertTrue($event->isHandled()); + $this->assertTrue($event->isCreated()); + $this->assertSame('gb-9', $event->getGovernanceBodyId()); + + $this->assertCount(1, $announced); + $conclusion = $announced[0]; + $this->assertInstanceOf(GovernanceBodyCreatedEvent::class, $conclusion); + $this->assertSame('corr-1', $conclusion->getCorrelationId()); + $this->assertSame('gb-9', $conclusion->getGovernanceBodyId()); + $this->assertSame('dossiq', $conclusion->getSourceApp()); + $this->assertSame('cmte-1', $conclusion->getExternalReference()); + $this->assertTrue($conclusion->isCreated()); + + }//end testHandledCommandWritesResultSlotsAndAnnounces() + + /** + * A failing command leaves the event unhandled and throws nothing. + * + * @return void + */ + public function testFailureLeavesEventUnhandledAndThrowsNothing(): void { + $service = $this->createMock(GovernanceBodyCommandService::class); + $service->method('upsert')->willThrowException(new RuntimeException('register down')); + + $dispatcher = $this->createMock(IEventDispatcher::class); + $dispatcher->expects($this->never())->method('dispatchTyped'); + + $event = $this->event(); + $listener = new GovernanceBodyRequestedListener( + $service, + $dispatcher, + $this->createMock(LoggerInterface::class), + ); + + $listener->handle($event); + + $this->assertFalse($event->isHandled()); + $this->assertSame('', $event->getGovernanceBodyId()); + $this->assertFalse($event->isCreated()); + + }//end testFailureLeavesEventUnhandledAndThrowsNothing() + + /** + * A matched body reports created = false. + * + * @return void + */ + public function testMatchedBodyReportsNotCreated(): void { + $service = $this->createMock(GovernanceBodyCommandService::class); + $service->method('upsert')->willReturn(['id' => 'gb-9', 'created' => false]); + + $event = $this->event(); + $listener = new GovernanceBodyRequestedListener( + $service, + $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), + ); + $listener->handle($event); + + $this->assertTrue($event->isHandled()); + $this->assertFalse($event->isCreated()); + + }//end testMatchedBodyReportsNotCreated() + + /** + * An unrelated event passes through untouched. + * + * @return void + */ + public function testUnrelatedEventIsIgnored(): void { + $service = $this->createMock(GovernanceBodyCommandService::class); + $service->expects($this->never())->method('upsert'); + + $listener = new GovernanceBodyRequestedListener( + $service, + $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), + ); + + $listener->handle(new class extends Event { + }); + + $this->addToAssertionCount(1); + + }//end testUnrelatedEventIsIgnored() + + /** + * The four stated fields reach the service alongside the attribute bag. + * + * @return void + */ + public function testStatedFieldsReachTheService(): void { + $seen = []; + $service = $this->createMock(GovernanceBodyCommandService::class); + $service->method('upsert')->willReturnCallback( + static function (string $app, string $ref, array $body, array $members) use (&$seen): array { + $seen = ['app' => $app, 'ref' => $ref, 'body' => $body, 'members' => $members]; + + return ['id' => 'gb-9', 'created' => true]; + } + ); + + $listener = new GovernanceBodyRequestedListener( + $service, + $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), + ); + $listener->handle($this->event()); + + $this->assertSame('dossiq', $seen['app']); + $this->assertSame('cmte-1', $seen['ref']); + $this->assertSame('Bezwaarcommissie sociaal domein', $seen['body']['name']); + $this->assertSame('advisory-body', $seen['body']['bodyType']); + $this->assertSame('social_domain', $seen['body']['domain']); + $this->assertTrue($seen['body']['active']); + $this->assertSame('Awb 7:13', $seen['body']['statutoryBasis']); + $this->assertSame([['uid' => 'alice', 'role' => 'chair']], $seen['members']); + + }//end testStatedFieldsReachTheService() + +}//end class diff --git a/tests/Unit/Service/ApprovalRouteServiceTest.php b/tests/Unit/Service/ApprovalRouteServiceTest.php index a0364f9ec..1a56d55cf 100644 --- a/tests/Unit/Service/ApprovalRouteServiceTest.php +++ b/tests/Unit/Service/ApprovalRouteServiceTest.php @@ -17,7 +17,7 @@ namespace OCA\Decidiq\Tests\Unit\Service; use OCA\Decidiq\Service\ApprovalRouteService; -use OCA\Decidiq\Service\ApprovalRouteStore; +use OCA\Decidiq\Service\RegisterObjectStore; use OCA\OpenRegister\Contract\ObjectEntityInterface; use OCA\OpenRegister\Contract\ObjectServiceInterface; use PHPUnit\Framework\TestCase; @@ -162,7 +162,7 @@ function ( static fn (array $config = []): array => $state->findAll($config) ); - return new ApprovalRouteService(new ApprovalRouteStore($facade)); + return new ApprovalRouteService(new RegisterObjectStore($facade)); } /** diff --git a/tests/Unit/Service/GovernanceBodyCommandServiceTest.php b/tests/Unit/Service/GovernanceBodyCommandServiceTest.php new file mode 100644 index 000000000..363a13b08 --- /dev/null +++ b/tests/Unit/Service/GovernanceBodyCommandServiceTest.php @@ -0,0 +1,453 @@ + + * SPDX-License-Identifier: EUPL-1.2 + * + * @category Test + * @package OCA\Decidiq\Tests\Unit\Service + * @author Conduction B.V. + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 + * @link https://github.com/ConductionNL/decidiq + */ + +declare(strict_types=1); + +namespace OCA\Decidiq\Tests\Unit\Service; + +use OCA\Decidiq\Service\GovernanceBodyCommandService; +use OCA\Decidiq\Service\RegisterObjectStore; +use OCA\OpenRegister\Contract\ObjectEntityInterface; +use OCA\OpenRegister\Contract\ObjectServiceInterface; +use PHPUnit\Framework\TestCase; +use RuntimeException; + +/** + * Covers the cross-app governance-body command engine. + * + * Every idempotency assertion here calls the seam TWICE and then COUNTS rows. + * A test that calls it once cannot tell an idempotent write from a duplicating + * one — it sees a body either way — which is exactly how a fan-out migration + * ships looking correct and mints a second Person per member on the re-run. + */ +class GovernanceBodyCommandServiceTest extends TestCase { + + /** + * In-memory OpenRegister stand-in. + * + * @var object + */ + private object $objectService; + + /** + * Build the fake register. + * + * @return void + */ + protected function setUp(): void { + parent::setUp(); + + $this->objectService = new class { + /** + * Stored rows, keyed by schema then uuid. + * + * @var array>> + */ + public array $rows = ['governance-body' => [], 'person' => [], 'membership' => []]; + + /** + * Schemas whose next write must throw, keyed by schema slug. + * + * @var array + */ + public array $failWriteAt = []; + + /** + * Writes seen per schema. + * + * @var array + */ + public array $writes = []; + + /** + * Uuid counter. + * + * @var int + */ + private int $counter = 0; + + /** + * Create or patch a row. + * + * @param array $object The object or patch. + * @param string $register The register. + * @param string $schema The schema. + * @param string|null $uuid The uuid. + * + * @return array The stored row. + */ + public function saveObject(array $object, string $register, string $schema, ?string $uuid = null): array { + $this->writes[$schema] = (($this->writes[$schema] ?? 0) + 1); + if (($this->failWriteAt[$schema] ?? null) === $this->writes[$schema]) { + throw new RuntimeException('simulated write failure on ' . $schema); + } + + if ($uuid === null) { + $this->counter++; + $uuid = $schema . '-' . $this->counter; + $this->rows[$schema][$uuid] = ($object + ['id' => $uuid]); + + return $this->rows[$schema][$uuid]; + } + + $this->rows[$schema][$uuid] = (array_merge(($this->rows[$schema][$uuid] ?? []), $object) + ['id' => $uuid]); + + return $this->rows[$schema][$uuid]; + } + + /** + * Filter the stored rows. + * + * @param array $config The query config. + * + * @return array> The rows. + */ + public function findAll(array $config): array { + $filters = $config['filters']; + $schema = $filters['schema']; + unset($filters['register'], $filters['schema']); + + $out = []; + foreach (($this->rows[$schema] ?? []) as $row) { + $matches = true; + foreach ($filters as $key => $value) { + if (($row[$key] ?? null) !== $value) { + $matches = false; + break; + } + } + + if ($matches === true) { + $out[] = $row; + } + } + + return $out; + } + }; + + }//end setUp() + + /** + * The service under test. + * + * @return GovernanceBodyCommandService The service. + */ + private function service(): GovernanceBodyCommandService { + $state = $this->objectService; + $facade = $this->createMock(ObjectServiceInterface::class); + $facade->method('saveObject')->willReturnCallback( + function ( + array $object, + ?array $extend = [], + string|int|null $register = null, + string|int|null $schema = null, + ?string $uuid = null, + ) use ($state): ObjectEntityInterface { + $row = $state->saveObject($object, (string)$register, (string)$schema, $uuid); + + $entity = $this->createMock(ObjectEntityInterface::class); + $entity->method('jsonSerialize')->willReturn($row); + + return $entity; + } + ); + $facade->method('findAll')->willReturnCallback( + static fn (array $config = []): array => $state->findAll($config) + ); + + return new GovernanceBodyCommandService(new RegisterObjectStore($facade)); + + }//end service() + + /** + * A committee command body. + * + * @param boolean $active The active flag. + * + * @return array The body fields. + */ + private function body(bool $active = true): array { + return [ + 'name' => 'Bezwaarcommissie sociaal domein', + 'bodyType' => 'advisory-body', + 'domain' => 'social_domain', + 'active' => $active, + 'quorum' => 3, + 'statutoryBasis' => 'Awb 7:13', + ]; + + }//end body() + + /** + * A three-seat roster. + * + * @param string $aliceRole Alice's role. + * + * @return array> The roster. + */ + private function roster(string $aliceRole = 'chair'): array { + return [ + ['uid' => 'alice', 'role' => $aliceRole], + ['uid' => 'bob', 'role' => 'member'], + ['uid' => 'carol', 'role' => 'secretary', 'external' => true], + ]; + + }//end roster() + + /** + * Count stored rows of one schema. + * + * @param string $schema The schema slug. + * + * @return int The count. + */ + private function countRows(string $schema): int { + return count($this->objectService->rows[$schema]); + + }//end countRows() + + /** + * REQ-GBE-002: a command raises a body and reports its id. + * + * @return void + */ + public function testCommandRaisesBodyAndReportsId(): void { + $result = $this->service()->upsert('dossiq', 'cmte-1', $this->body(), $this->roster()); + + $this->assertTrue($result['created']); + $this->assertNotSame('', $result['id']); + $this->assertSame(1, $this->countRows('governance-body')); + + $stored = $this->objectService->rows['governance-body'][$result['id']]; + $this->assertSame('dossiq', $stored['sourceApp']); + $this->assertSame('cmte-1', $stored['externalReference']); + $this->assertSame('Awb 7:13', $stored['statutoryBasis']); + $this->assertSame(3, $stored['quorum']); + + }//end testCommandRaisesBodyAndReportsId() + + /** + * REQ-GBE-003: a second identical command creates one body, not two. + * + * @return void + */ + public function testSecondIdenticalCommandCreatesOneBody(): void { + $service = $this->service(); + $first = $service->upsert('dossiq', 'cmte-1', $this->body(), $this->roster()); + $second = $service->upsert('dossiq', 'cmte-1', $this->body(), $this->roster()); + + $this->assertSame(1, $this->countRows('governance-body')); + $this->assertSame($first['id'], $second['id']); + $this->assertTrue($first['created']); + $this->assertFalse($second['created']); + + }//end testSecondIdenticalCommandCreatesOneBody() + + /** + * REQ-GBE-003: the roster fan-out is idempotent too. + * + * @return void + */ + public function testSecondIdenticalCommandCreatesOneSeatPerMember(): void { + $service = $this->service(); + $service->upsert('dossiq', 'cmte-1', $this->body(), $this->roster()); + $service->upsert('dossiq', 'cmte-1', $this->body(), $this->roster()); + + $this->assertSame(3, $this->countRows('person')); + $this->assertSame(3, $this->countRows('membership')); + + }//end testSecondIdenticalCommandCreatesOneSeatPerMember() + + /** + * REQ-GBE-003: a changed role updates the seat rather than adding one. + * + * @return void + */ + public function testChangedRoleUpdatesTheSeat(): void { + $service = $this->service(); + $service->upsert('dossiq', 'cmte-1', $this->body(), $this->roster('member')); + $service->upsert('dossiq', 'cmte-1', $this->body(), $this->roster('chair')); + + $this->assertSame(3, $this->countRows('membership')); + + $alice = null; + foreach ($this->objectService->rows['person'] as $row) { + if ($row['nextcloudUserId'] === 'alice') { + $alice = $row['id']; + } + } + + $roles = []; + foreach ($this->objectService->rows['membership'] as $row) { + if ($row['person'] === $alice) { + $roles[] = $row['role']; + } + } + + $this->assertSame(['chair'], $roles); + + }//end testChangedRoleUpdatesTheSeat() + + /** + * REQ-GBE-003: a different externalReference is a different body. + * + * @return void + */ + public function testDifferentReferenceIsADifferentBody(): void { + $service = $this->service(); + $service->upsert('dossiq', 'cmte-1', $this->body(), []); + $service->upsert('dossiq', 'cmte-2', $this->body(), []); + + $this->assertSame(2, $this->countRows('governance-body')); + + }//end testDifferentReferenceIsADifferentBody() + + /** + * REQ-GBE-004: a crash mid-fan-out leaves a body the next run completes. + * + * @return void + */ + public function testCrashMidRosterLeavesACompletableBody(): void { + // Writes to `membership`: 1 = alice, 2 = bob. Fail on bob. + $this->objectService->failWriteAt['membership'] = 2; + + $service = $this->service(); + try { + $service->upsert('dossiq', 'cmte-1', $this->body(), $this->roster()); + $this->fail('the simulated write failure should have propagated'); + } catch (RuntimeException $e) { + $this->assertStringContainsString('simulated write failure', $e->getMessage()); + } + + $this->assertSame(1, $this->countRows('governance-body'), 'the body is written before the roster'); + $this->assertSame(1, $this->countRows('membership')); + + $this->objectService->failWriteAt = []; + $result = $service->upsert('dossiq', 'cmte-1', $this->body(), $this->roster()); + + $this->assertFalse($result['created'], 'the re-run matches the half-written body'); + $this->assertSame(1, $this->countRows('governance-body')); + $this->assertSame(3, $this->countRows('membership')); + $this->assertSame(3, $this->countRows('person')); + + }//end testCrashMidRosterLeavesACompletableBody() + + /** + * REQ-GBE-005: an omitted `active` is refused, not defaulted. + * + * @return void + */ + public function testOmittedActiveIsRefused(): void { + $body = $this->body(); + unset($body['active']); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessageMatches('/never defaulted/'); + + try { + $this->service()->upsert('dossiq', 'cmte-1', $body, $this->roster()); + } finally { + $this->assertSame(0, $this->countRows('governance-body'), 'nothing is written on a refusal'); + } + + }//end testOmittedActiveIsRefused() + + /** + * REQ-GBE-005: an archived committee stays archived across a re-run. + * + * @return void + */ + public function testArchivedBodyStaysArchivedAcrossRerun(): void { + $service = $this->service(); + $first = $service->upsert('dossiq', 'cmte-1', $this->body(active: false), []); + $service->upsert('dossiq', 'cmte-1', $this->body(active: false), []); + + $this->assertFalse($this->objectService->rows['governance-body'][$first['id']]['active']); + + }//end testArchivedBodyStaysArchivedAcrossRerun() + + /** + * A producer cannot overwrite the provenance pair through the attribute bag. + * + * @return void + */ + public function testProducerCannotOverwriteTheProvenancePair(): void { + $body = ($this->body() + ['sourceApp' => 'evil', 'externalReference' => 'other']); + $result = $this->service()->upsert('dossiq', 'cmte-1', $body, []); + + $stored = $this->objectService->rows['governance-body'][$result['id']]; + $this->assertSame('dossiq', $stored['sourceApp']); + $this->assertSame('cmte-1', $stored['externalReference']); + + }//end testProducerCannotOverwriteTheProvenancePair() + + /** + * An unknown membership role is refused rather than stored. + * + * @return void + */ + public function testUnknownRoleIsRefused(): void { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessageMatches('/Unknown membership role/'); + + $this->service()->upsert( + 'dossiq', + 'cmte-1', + $this->body(), + [['uid' => 'alice', 'role' => 'grand-vizier']] + ); + + }//end testUnknownRoleIsRefused() + + /** + * A command without its provenance pair is refused. + * + * @return void + */ + public function testMissingProvenanceIsRefused(): void { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessageMatches('/sourceApp and externalReference/'); + + $this->service()->upsert('', 'cmte-1', $this->body(), []); + + }//end testMissingProvenanceIsRefused() + + /** + * Awb 7:13(2): the secretary's external flag survives the fan-out. + * + * @return void + */ + public function testExternalFlagIsCarriedOntoTheMembership(): void { + $this->service()->upsert('dossiq', 'cmte-1', $this->body(), $this->roster()); + + $carol = null; + foreach ($this->objectService->rows['person'] as $row) { + if ($row['nextcloudUserId'] === 'carol') { + $carol = $row['id']; + } + } + + $external = null; + foreach ($this->objectService->rows['membership'] as $row) { + if ($row['person'] === $carol) { + $external = $row['external']; + } + } + + $this->assertTrue($external); + + }//end testExternalFlagIsCarriedOntoTheMembership() + +}//end class From 044588b74627125a800e4dfcacc61586ed48651c Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Mon, 31 Aug 2026 05:12:36 +0200 Subject: [PATCH 12/21] feat(approval): add the cross-app command seam for approval routes (#1028) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(governance): add the cross-app command seam for governance bodies decidiq#874 made GovernanceBody able to hold a Dutch bezwaaradviescommissie and added a REST write path for it. That path is the door for EXTERNAL callers. An in-process app-to-app command cannot use it: ADR-041 says a cross-app command travels as a typed event (gate-27 enforces it), and an in-process HTTP call to our own instance has no session, so ApiController::write() refuses it — which is exactly the state a background migration runs in. So this adds the missing door, copying the DecisionRequestedEvent shape: - GovernanceBodyRequestedEvent / GovernanceBodyCreatedEvent - GovernanceBodyCommandService — the idempotent upsert plus the roster fan-out to Person + Membership - GovernanceBodyRequestedListener, registered beside registerDecisionEvents - sourceApp + externalReference on GovernanceBody, additively Every write is preceded by a resolve. The body resolves on (sourceApp, externalReference), a Person on nextcloudUserId, a Membership on its (person, governanceBody) pair, so a re-run of a consuming migration updates rather than minting a second of each. The body is saved and its id read BEFORE the first membership write, so a crash mid-fan-out leaves a body the next run completes instead of orphans pointing at nothing. `active` is refused when absent rather than defaulted to true: it is the one field the consuming app throws on, and a silent default would route objections to a disbanded committee with nothing erroring. Every idempotency test calls the seam TWICE and counts rows. A test that calls it once sees a body either way and cannot tell an idempotent write from a duplicating one. Mutation-checked: making findBody() always miss, making the Person lookup always miss, and defaulting `active` to true each turn the suite red. ApprovalRouteStore is renamed RegisterObjectStore. It was already generic (save/findAll/normalise over decidiq's register) and this change is its second consumer; a second copy would have been the "second store that drifts" hazard in miniature. Unblocks dossiq's migrate-committees-to-decidiq, which is BLOCKED on precisely this seam and asks nothing else of decidiq. Verified: 1241 unit tests pass (22 skipped, pre-existing), PHPCS/PHPMD/PHPStan/ Psalm clean on every changed file, and all 73 applicable hydra gates green including gate-27 no-phantom-cross-app-rpc. * fix(ci): give the cross-app listeners their own registrar, and catalogue the two new schema titles Two real CI failures on this branch, both caused by it. phpmd: adding a second event/listener pair took DomainServiceRegistrar to a coupling of 14, over the threshold — measured 0 on development. The registrar's job is registration, so the coupling is inherent; the fix is that the inbound cross-app surface is its own concern. CrossAppEventRegistrar now holds it as one map in one file, which also means adding a command is one line. This extraction was already in the stacked approval-route PR. It belongs here instead: this is the branch where the threshold is first crossed, and a stacked PR must not be what makes its parent green. check:schema-l10n: `Source app` and `External reference` are new schema property titles with no catalogue key, so they would render in English inside an otherwise translated form. Added to en.json and nl.json and rebuilt the js catalogues. The ratchet is back to its 1634 baseline. The third red check, "Conflict markers and PHP syntax", was CANCELLED rather than failed — it re-runs on this push. Verified at CI SCOPE, not just on the changed files: phpmd, phpcs, phpstan and psalm clean across the whole tree, 1241 unit tests pass, and all four npm checks pass. check:manifest needs Ajv resolvable; without it the script silently falls back to a structural lint and reports a PRE-EXISTING page-type finding, which is worth knowing before someone reads that fallback as a regression. * feat(approval): add the cross-app command seam for approval routes `approval-routes` shipped the engine and named the consumer it was built for: dossiq's parafering, "implemented today in dossiq, where it works", which "does not belong there". That migration still cannot start, for the same reason governance bodies could not move until the previous commit fixed it — the engine is reachable only over REST, and REST is the wrong door for an in-process app-to-app command (ADR-041, gate-27), besides refusing a request with no session, which is the state a migration runs in. So this adds the door: - ApprovalRouteRequestedEvent — hold this route, and optionally start one subject travelling it in the same command - ApprovalActionRequestedEvent — record one actor's action - ApprovalRouteConcludedEvent — emitted when an action decides the final stage - ApprovalRouteCommandService, two listeners, and `sourceApp` + `externalReference` on ApprovalRoute as the idempotency key 🔴 IT IS NOT A SECOND ENGINE, and that is the design constraint. Which stage is active, what a return does, which actors may act, whether a mandatory stage may be skipped: all of it stays in ApprovalRouteService and none of it is restated. testSeamAndServiceCannotDiverge advances two identical subjects — one through the seam, one through the service — and asserts their stage rows are identical, so a seam that grew its own rules fails rather than drifting. Two smaller decisions worth reading: The listener carries the engine's REFUSAL REASON back, not a bare false. "You are not the named actor" and "there is nothing to act on" need different handling by the producer and a boolean collapses them. No producer-supplied `step` reaches the engine. The engine decides which stage is active; accepting a step number would let an action be filed against a stage nobody is waiting on. `ApprovalRouteService::stagesFor()` is promoted to public so the seam can answer "did that finish the route" by asking the engine rather than running a second query over decision-stage rows. The event registrations move out of DomainServiceRegistrar into a new CrossAppEventRegistrar. What was one event/listener pair is now four, and each pair cost that class two imports: it went from clean on development to a coupling of 14 after the governance seam and 18 after this one. Splitting fixes the measurement and reads better — the whole inbound cross-app surface is now one map in one file. Verified: 1262 unit tests pass (22 skipped, pre-existing), PHPCS/PHPMD/PHPStan/ Psalm clean on every changed file, the fragment merge run through a real deep-merge rather than assumed, and ALL 75 applicable hydra gates green with all 75 actually running. Mutation-checked: making the route lookup always miss, never reporting completion, and dropping the empty-steps guard each turn the suite red. Stacked on #1019 — it needs the RegisterObjectStore rename. Unblocks dossiq's parafering migration. * fix(l10n): catalogue the two new approval-route property descriptions check:schema-l10n counts property DESCRIPTIONS as well as titles, so the sourceApp/externalReference helper text on ApprovalRoute would have rendered in English inside an otherwise translated form. The ratchet is back to its 1634 baseline. * fix(l10n): resolve the en.json merge conflict the previous commit carried The merge resolved nl.json but left en.json's conflict markers in place, and they were committed. Invalid JSON there is silent in the worst way: check:schema-l10n could not parse the catalogue, so it reported 1948 of 1948 strings uncovered — a total failure that reads like a catastrophic regression rather than an unparseable file. Both sides of that conflict ADD keys, so both are kept. Artefacts rebuilt; the ratchet is back at its 1632 baseline. --------- Co-authored-by: Ruben van der Linde --- l10n/en.js | 2 + l10n/en.json | 2 + l10n/nl.js | 2 + l10n/nl.json | 2 + .../Registrar/CrossAppEventRegistrar.php | 24 +- lib/Event/ApprovalActionRequestedEvent.php | 353 +++++++++++++ lib/Event/ApprovalRouteConcludedEvent.php | 120 +++++ lib/Event/ApprovalRouteRequestedEvent.php | 354 +++++++++++++ .../ApprovalActionRequestedListener.php | 154 ++++++ .../ApprovalRouteRequestedListener.php | 118 +++++ lib/Service/ApprovalRouteCommandService.php | 304 +++++++++++ lib/Service/ApprovalRouteService.php | 9 +- .../register.d/73-approval-route-events.json | 26 + .../changes/approval-route-events/proposal.md | 99 ++++ .../specs/approval-route-events/spec.md | 147 ++++++ .../changes/approval-route-events/tasks.md | 52 ++ .../Listener/ApprovalRouteListenersTest.php | 323 ++++++++++++ .../ApprovalRouteCommandServiceTest.php | 474 ++++++++++++++++++ 18 files changed, 2558 insertions(+), 7 deletions(-) create mode 100644 lib/Event/ApprovalActionRequestedEvent.php create mode 100644 lib/Event/ApprovalRouteConcludedEvent.php create mode 100644 lib/Event/ApprovalRouteRequestedEvent.php create mode 100644 lib/Listener/ApprovalActionRequestedListener.php create mode 100644 lib/Listener/ApprovalRouteRequestedListener.php create mode 100644 lib/Service/ApprovalRouteCommandService.php create mode 100644 lib/Settings/register.d/73-approval-route-events.json create mode 100644 openspec/changes/approval-route-events/proposal.md create mode 100644 openspec/changes/approval-route-events/specs/approval-route-events/spec.md create mode 100644 openspec/changes/approval-route-events/tasks.md create mode 100644 tests/Unit/Listener/ApprovalRouteListenersTest.php create mode 100644 tests/Unit/Service/ApprovalRouteCommandServiceTest.php diff --git a/l10n/en.js b/l10n/en.js index 86879498e..e20f12c57 100644 --- a/l10n/en.js +++ b/l10n/en.js @@ -1741,6 +1741,8 @@ OC.L10N.register( "Today": "Today", "Source app": "Source app", "External reference": "External reference", + "App id of the fleet app this route was held on behalf of (e.g. dossiq). Empty for routes authored in decidiq itself. Half of the idempotency key; never an authorization input.": "App id of the fleet app this route was held on behalf of (e.g. dossiq). Empty for routes authored in decidiq itself. Half of the idempotency key; never an authorization input.", + "The producing app's own id for the route this one was migrated from. Paired with sourceApp it identifies the origin, so a repeated command updates this route rather than creating another.": "The producing app's own id for the route this one was migrated from. Paired with sourceApp it identifies the origin, so a repeated command updates this route rather than creating another.", "consultationType=tender: the winning party recorded when the award decision is made (status=awarded). Decidiq owns publish/manage/award only; authoring is procest and bidding is pipelinq.": "consultationType=tender: the winning party recorded when the award decision is made (status=awarded). Decidiq owns publish/manage/award only; authoring is procest and bidding is pipelinq.", "schema.org annotation matching the ORI type (ChooseAction / Event / CreativeWork).": "schema.org annotation matching the ORI type (ChooseAction / Event / CreativeWork).", "consultationType=tender: public tender reference/notice number.": "consultationType=tender: public tender reference/notice number.", diff --git a/l10n/en.json b/l10n/en.json index ec7a986ff..eab292fe3 100644 --- a/l10n/en.json +++ b/l10n/en.json @@ -1740,6 +1740,8 @@ "Today": "Today", "Source app": "Source app", "External reference": "External reference", + "App id of the fleet app this route was held on behalf of (e.g. dossiq). Empty for routes authored in decidiq itself. Half of the idempotency key; never an authorization input.": "App id of the fleet app this route was held on behalf of (e.g. dossiq). Empty for routes authored in decidiq itself. Half of the idempotency key; never an authorization input.", + "The producing app's own id for the route this one was migrated from. Paired with sourceApp it identifies the origin, so a repeated command updates this route rather than creating another.": "The producing app's own id for the route this one was migrated from. Paired with sourceApp it identifies the origin, so a repeated command updates this route rather than creating another.", "consultationType=tender: the winning party recorded when the award decision is made (status=awarded). Decidiq owns publish/manage/award only; authoring is procest and bidding is pipelinq.": "consultationType=tender: the winning party recorded when the award decision is made (status=awarded). Decidiq owns publish/manage/award only; authoring is procest and bidding is pipelinq.", "schema.org annotation matching the ORI type (ChooseAction / Event / CreativeWork).": "schema.org annotation matching the ORI type (ChooseAction / Event / CreativeWork).", "consultationType=tender: public tender reference/notice number.": "consultationType=tender: public tender reference/notice number.", diff --git a/l10n/nl.js b/l10n/nl.js index eb803c05e..ce729f3bc 100644 --- a/l10n/nl.js +++ b/l10n/nl.js @@ -2040,6 +2040,8 @@ OC.L10N.register( "{states} states, {transitions} transitions": "{states} statussen, {transitions} overgangen", "Source app": "Bronapplicatie", "External reference": "Externe referentie", + "App id of the fleet app this route was held on behalf of (e.g. dossiq). Empty for routes authored in decidiq itself. Half of the idempotency key; never an authorization input.": "App-id van de applicatie waarvoor deze route wordt bewaard (bijvoorbeeld dossiq). Leeg voor routes die in decidiq zelf zijn gemaakt. De helft van de idempotentiesleutel; nooit een autorisatiegrond.", + "The producing app's own id for the route this one was migrated from. Paired with sourceApp it identifies the origin, so a repeated command updates this route rather than creating another.": "Het eigen id dat de bronapplicatie gebruikt voor de route waaruit deze is overgenomen. Samen met sourceApp bepaalt het de herkomst, zodat een herhaalde opdracht deze route bijwerkt in plaats van een tweede aanmaakt.", "Which kind of organisation is this for?": "Voor wat voor organisatie is dit?", "Pick the organisation this app runs for and you get a worked example of it: bodies, meetings, decisions and templates that fit. Installing the app plants nothing on its own, so this is the only step that adds data. Choose \"None\" on a production install.": "Kies de organisatie waarvoor deze app draait en je krijgt een uitgewerkt voorbeeld: organen, vergaderingen, besluiten en sjablonen die daarbij passen. De app zet zelf niets klaar, dus dit is de enige stap die gegevens toevoegt. Kies \"Geen\" op een productieomgeving.", "Load the example data": "Laad de voorbeeldgegevens", diff --git a/l10n/nl.json b/l10n/nl.json index c28f11d4d..a830b49ed 100644 --- a/l10n/nl.json +++ b/l10n/nl.json @@ -2039,6 +2039,8 @@ "{states} states, {transitions} transitions": "{states} statussen, {transitions} overgangen", "Source app": "Bronapplicatie", "External reference": "Externe referentie", + "App id of the fleet app this route was held on behalf of (e.g. dossiq). Empty for routes authored in decidiq itself. Half of the idempotency key; never an authorization input.": "App-id van de applicatie waarvoor deze route wordt bewaard (bijvoorbeeld dossiq). Leeg voor routes die in decidiq zelf zijn gemaakt. De helft van de idempotentiesleutel; nooit een autorisatiegrond.", + "The producing app's own id for the route this one was migrated from. Paired with sourceApp it identifies the origin, so a repeated command updates this route rather than creating another.": "Het eigen id dat de bronapplicatie gebruikt voor de route waaruit deze is overgenomen. Samen met sourceApp bepaalt het de herkomst, zodat een herhaalde opdracht deze route bijwerkt in plaats van een tweede aanmaakt.", "Which kind of organisation is this for?": "Voor wat voor organisatie is dit?", "Pick the organisation this app runs for and you get a worked example of it: bodies, meetings, decisions and templates that fit. Installing the app plants nothing on its own, so this is the only step that adds data. Choose \"None\" on a production install.": "Kies de organisatie waarvoor deze app draait en je krijgt een uitgewerkt voorbeeld: organen, vergaderingen, besluiten en sjablonen die daarbij passen. De app zet zelf niets klaar, dus dit is de enige stap die gegevens toevoegt. Kies \"Geen\" op een productieomgeving.", "Load the example data": "Laad de voorbeeldgegevens", diff --git a/lib/AppInfo/Registrar/CrossAppEventRegistrar.php b/lib/AppInfo/Registrar/CrossAppEventRegistrar.php index 7ca3e3ba9..f9df2a7e4 100644 --- a/lib/AppInfo/Registrar/CrossAppEventRegistrar.php +++ b/lib/AppInfo/Registrar/CrossAppEventRegistrar.php @@ -5,9 +5,10 @@ * * Wires the typed events other fleet apps dispatch to command Decidiq, and the * listeners that answer them. Split out of DomainServiceRegistrar because the - * set grew: what was one event/listener pair for decisions is now two, and each - * pair costs that class two more imports — enough to push it past the coupling - * threshold, which is how this extraction was found rather than guessed. + * set grew: what was one event/listener pair for decisions is now four, one per + * thing another app can ask Decidiq to do, and each pair costs that class two + * more imports — enough to push it past the coupling threshold, which is how + * this extraction was found rather than guessed. * * Per ADR-041 a cross-app COMMAND travels as a typed event. Decidiq's REST * controllers are the door for EXTERNAL callers; they refuse a request with no @@ -22,7 +23,7 @@ * * @link https://conduction.nl * - * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md * * SPDX-FileCopyrightText: 2026 Conduction B.V. * SPDX-License-Identifier: EUPL-1.2 @@ -32,8 +33,12 @@ namespace OCA\Decidiq\AppInfo\Registrar; +use OCA\Decidiq\Event\ApprovalActionRequestedEvent; +use OCA\Decidiq\Event\ApprovalRouteRequestedEvent; use OCA\Decidiq\Event\DecisionRequestedEvent; use OCA\Decidiq\Event\GovernanceBodyRequestedEvent; +use OCA\Decidiq\Listener\ApprovalActionRequestedListener; +use OCA\Decidiq\Listener\ApprovalRouteRequestedListener; use OCA\Decidiq\Listener\DecisionRequestedListener; use OCA\Decidiq\Listener\GovernanceBodyRequestedListener; use OCP\AppFramework\Bootstrap\IRegistrationContext; @@ -41,7 +46,7 @@ /** * Registers every inbound cross-app command listener. * - * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md */ class CrossAppEventRegistrar { @@ -60,6 +65,13 @@ class CrossAppEventRegistrar { // Hold a governance body — a committee, a board — with its roster. GovernanceBodyRequestedEvent::class => GovernanceBodyRequestedListener::class, + + // Hold a sign-off route, and travel a subject down it. Both delegate to + // the EXISTING ApprovalRouteService: these add a door, not a second + // engine, so the event path and the REST path cannot answer differently + // for the same action. + ApprovalRouteRequestedEvent::class => ApprovalRouteRequestedListener::class, + ApprovalActionRequestedEvent::class => ApprovalActionRequestedListener::class, ]; /** @@ -69,7 +81,7 @@ class CrossAppEventRegistrar { * * @return void * - * @spec openspec/changes/governance-body-events/specs/governance-body-events/spec.md + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md */ public function register(IRegistrationContext $context): void { foreach (self::COMMANDS as $event => $listener) { diff --git a/lib/Event/ApprovalActionRequestedEvent.php b/lib/Event/ApprovalActionRequestedEvent.php new file mode 100644 index 000000000..2661f9c7c --- /dev/null +++ b/lib/Event/ApprovalActionRequestedEvent.php @@ -0,0 +1,353 @@ + + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * @link https://conduction.nl + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace OCA\Decidiq\Event; + +use OCP\EventDispatcher\Event; + +/** + * A consumer app records an approval action. + * + * 🔴 THE ACTOR IS A REQUEST FIELD HERE, and that is safe only because this event + * is IN-PROCESS. `ApprovalRouteController` takes the actor from the SESSION and + * never from the body, precisely so no caller can sign off as somebody else. A + * producer dispatching this event is trusted code in the same PHP process, which + * is a different trust boundary from an HTTP request. Any future path that lets + * an untrusted party construct this event must resolve the actor itself. + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ +class ApprovalActionRequestedEvent extends Event { + + /** + * Whether the action was recorded (result slot). + * + * @var boolean + */ + private bool $recorded = false; + + /** + * Whether this action decided the final stage (result slot). + * + * @var boolean + */ + private bool $completed = false; + + /** + * Whether Decidiq handled this command (result slot). + * + * @var boolean + */ + private bool $handled = false; + + /** + * The reason the engine refused, when it did (result slot). + * + * @var string + */ + private string $refusal = ''; + + /** + * Construct the command event. + * + * @param string $sourceApp App id of the producer + * @param string $subject The subject travelling the route + * @param string $actor Nextcloud UID of the person acting + * @param string $action The verb: approved, returned, advised, skipped or endorsed + * @param integer $returnToStep The step a `returned` action sends the route back to + * @param string $comment Comment or reason + * @param string $advice Advisory text, for advisory stages + * @param string $actorType Whether the actor acted directly or as a delegate + * @param string $onBehalfOf The principal, when acting as a delegate + * @param string $mandate Mandate reference for a delegate action + * @param string $correlationId Correlation id echoed on the conclusion event + * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) This parameter list is a + * PUBLISHED CROSS-APP CONTRACT constructed POSITIONALLY through a + * class-string by consumers that must stay installable without Decidiq. + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function __construct( + private readonly string $sourceApp, + private readonly string $subject, + private readonly string $actor, + private readonly string $action, + private readonly int $returnToStep = 0, + private readonly string $comment = '', + private readonly string $advice = '', + private readonly string $actorType = 'user', + private readonly string $onBehalfOf = '', + private readonly string $mandate = '', + private readonly string $correlationId = '', + ) { + parent::__construct(); + + }//end __construct() + + /** + * Get the producing app id. + * + * @return string The app id + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getSourceApp(): string { + return $this->sourceApp; + + }//end getSourceApp() + + /** + * Get the subject travelling the route. + * + * @return string The subject id + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getSubject(): string { + return $this->subject; + + }//end getSubject() + + /** + * Get the acting Nextcloud UID. + * + * @return string The actor + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getActor(): string { + return $this->actor; + + }//end getActor() + + /** + * Get the action verb. + * + * @return string The verb + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getAction(): string { + return $this->action; + + }//end getAction() + + /** + * Get the step a return sends the route back to. + * + * @return integer The step number, or 0 + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getReturnToStep(): int { + return $this->returnToStep; + + }//end getReturnToStep() + + /** + * Get the comment. + * + * @return string The comment + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getComment(): string { + return $this->comment; + + }//end getComment() + + /** + * Get the advisory text. + * + * @return string The advice + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getAdvice(): string { + return $this->advice; + + }//end getAdvice() + + /** + * Get whether the actor acted directly or as a delegate. + * + * @return string The actor type + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getActorType(): string { + return $this->actorType; + + }//end getActorType() + + /** + * Get the principal, when acting as a delegate. + * + * @return string The principal's uid + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getOnBehalfOf(): string { + return $this->onBehalfOf; + + }//end getOnBehalfOf() + + /** + * Get the mandate reference. + * + * @return string The mandate + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getMandate(): string { + return $this->mandate; + + }//end getMandate() + + /** + * Get the correlation id. + * + * @return string The correlation id + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getCorrelationId(): string { + return $this->correlationId; + + }//end getCorrelationId() + + /** + * Whether the action was recorded. + * + * @return boolean The recorded flag + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function isRecorded(): bool { + return $this->recorded; + + }//end isRecorded() + + /** + * Record that the action was stored (result slot). + * + * @param boolean $recorded True when an action row was written + * + * @return void + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function setRecorded(bool $recorded): void { + $this->recorded = $recorded; + + }//end setRecorded() + + /** + * Whether this action decided the final stage. + * + * @return boolean The completed flag + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function isCompleted(): bool { + return $this->completed; + + }//end isCompleted() + + /** + * Record that the route completed (result slot). + * + * @param boolean $completed True when no stage is left active + * + * @return void + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function setCompleted(bool $completed): void { + $this->completed = $completed; + + }//end setCompleted() + + /** + * Whether Decidiq handled the command. + * + * @return boolean The handled flag + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function isHandled(): bool { + return $this->handled; + + }//end isHandled() + + /** + * Record that Decidiq handled the command (result slot). + * + * @param boolean $handled True when the command was applied + * + * @return void + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function setHandled(bool $handled): void { + $this->handled = $handled; + + }//end setHandled() + + /** + * The engine's reason for refusing, when it refused. + * + * The producer needs the REASON, not just the refusal: "you are not the + * named actor" and "there is nothing to act on" call for different handling, + * and a bare false collapses them. + * + * @return string The refusal reason, or an empty string + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getRefusal(): string { + return $this->refusal; + + }//end getRefusal() + + /** + * Record the engine's refusal reason (result slot). + * + * @param string $refusal The reason + * + * @return void + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function setRefusal(string $refusal): void { + $this->refusal = $refusal; + + }//end setRefusal() + +}//end class diff --git a/lib/Event/ApprovalRouteConcludedEvent.php b/lib/Event/ApprovalRouteConcludedEvent.php new file mode 100644 index 000000000..1f3fc994f --- /dev/null +++ b/lib/Event/ApprovalRouteConcludedEvent.php @@ -0,0 +1,120 @@ + + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * @link https://conduction.nl + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace OCA\Decidiq\Event; + +use OCP\EventDispatcher\Event; + +/** + * A subject has reached the end of its approval route. + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ +class ApprovalRouteConcludedEvent extends Event { + + /** + * Construct the conclusion event. + * + * @param string $subject The subject that finished travelling + * @param string $sourceApp App id of the producer the route was held for + * @param string $outcome The final stage's outcome + * @param string $actor Nextcloud UID of whoever decided the final stage + * @param string $correlationId Correlation id echoed from the request + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function __construct( + private readonly string $subject, + private readonly string $sourceApp, + private readonly string $outcome, + private readonly string $actor = '', + private readonly string $correlationId = '', + ) { + parent::__construct(); + + }//end __construct() + + /** + * Get the subject that finished travelling. + * + * @return string The subject id + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getSubject(): string { + return $this->subject; + + }//end getSubject() + + /** + * Get the producing app id. + * + * @return string The app id + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getSourceApp(): string { + return $this->sourceApp; + + }//end getSourceApp() + + /** + * Get the final stage's outcome. + * + * @return string The outcome + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getOutcome(): string { + return $this->outcome; + + }//end getOutcome() + + /** + * Get whoever decided the final stage. + * + * @return string The actor uid + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getActor(): string { + return $this->actor; + + }//end getActor() + + /** + * Get the correlation id echoed from the request. + * + * @return string The correlation id + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getCorrelationId(): string { + return $this->correlationId; + + }//end getCorrelationId() + +}//end class diff --git a/lib/Event/ApprovalRouteRequestedEvent.php b/lib/Event/ApprovalRouteRequestedEvent.php new file mode 100644 index 000000000..eae7cf6d1 --- /dev/null +++ b/lib/Event/ApprovalRouteRequestedEvent.php @@ -0,0 +1,354 @@ + + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * @link https://conduction.nl + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace OCA\Decidiq\Event; + +use OCP\EventDispatcher\Event; + +/** + * A consumer app asks Decidiq to hold an approval route. + * + * All request fields are immutable. Nextcloud typed dispatch is synchronous, so + * the result slots are written by Decidiq's listener and read by the producer + * right after dispatch — the same shape GovernanceBodyRequestedEvent uses. + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ +class ApprovalRouteRequestedEvent extends Event { + + /** + * The id of the route Decidiq held or matched (result slot). + * + * @var string|null + */ + private ?string $routeId = null; + + /** + * Whether the route was newly created (result slot). + * + * @var boolean + */ + private bool $created = false; + + /** + * How many stages the named subject was given (result slot). + * + * @var integer + */ + private int $stageCount = 0; + + /** + * Whether Decidiq handled this command (result slot). + * + * @var boolean + */ + private bool $handled = false; + + /** + * Construct the command event. + * + * @param string $sourceApp App id of the producer (e.g. dossiq) + * @param string $externalReference The producer's own id for the route + * @param string $name Admin-facing route name + * @param array> $steps Ordered steps of {order, stageType, actorType, actor, mandatory, label} + * @param string $subjectType What kind of thing travels this route (e.g. collegeadvies) + * @param string $description When this route applies + * @param boolean $isDefault Whether it is the default for its subjectType + * @param string $subject Optional subject id to start travelling the route now + * @param string $subjectSchema Schema slug of that subject + * @param string $actorId Nextcloud UID on whose behalf the command runs + * @param string $correlationId Correlation id echoed on the conclusion event + * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) This parameter list is a + * PUBLISHED CROSS-APP CONTRACT, not an internal signature. A consumer app + * constructs the event POSITIONALLY through a class-string so it stays + * installable without Decidiq. Collapsing these into an array would move the + * contract out of the signature and into an undocumented key set. + * + * @SuppressWarnings(PHPMD.BooleanArgumentFlag) `$isDefault` is a FIELD of + * ApprovalRoute, carried across the boundary unchanged, not a flag that + * selects between two behaviours of this constructor. The rule's usual + * remedy — split the method in two — would mean two event classes that + * differ only in one stored boolean. + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function __construct( + private readonly string $sourceApp, + private readonly string $externalReference, + private readonly string $name, + private readonly array $steps, + private readonly string $subjectType = '', + private readonly string $description = '', + private readonly bool $isDefault = false, + private readonly string $subject = '', + private readonly string $subjectSchema = '', + private readonly string $actorId = '', + private readonly string $correlationId = '', + ) { + parent::__construct(); + + }//end __construct() + + /** + * Get the producing app id. + * + * @return string The app id + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getSourceApp(): string { + return $this->sourceApp; + + }//end getSourceApp() + + /** + * Get the producer's own reference. + * + * @return string The external reference + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getExternalReference(): string { + return $this->externalReference; + + }//end getExternalReference() + + /** + * Get the route name. + * + * @return string The name + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getName(): string { + return $this->name; + + }//end getName() + + /** + * Get the ordered steps. + * + * @return array> The steps + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getSteps(): array { + return $this->steps; + + }//end getSteps() + + /** + * Get what kind of thing travels this route. + * + * @return string The subject type + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getSubjectType(): string { + return $this->subjectType; + + }//end getSubjectType() + + /** + * Get the route description. + * + * @return string The description + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getDescription(): string { + return $this->description; + + }//end getDescription() + + /** + * Whether this is the default route for its subject type. + * + * @return boolean The default flag + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function isDefault(): bool { + return $this->isDefault; + + }//end isDefault() + + /** + * Get the subject to start travelling the route, if any. + * + * @return string The subject id, or an empty string + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getSubject(): string { + return $this->subject; + + }//end getSubject() + + /** + * Get the subject's schema slug. + * + * @return string The schema slug + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getSubjectSchema(): string { + return $this->subjectSchema; + + }//end getSubjectSchema() + + /** + * Get the acting Nextcloud UID. + * + * @return string The actor id + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getActorId(): string { + return $this->actorId; + + }//end getActorId() + + /** + * Get the correlation id. + * + * @return string The correlation id + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getCorrelationId(): string { + return $this->correlationId; + + }//end getCorrelationId() + + /** + * Get the resolved route id. + * + * @return string The id, or an empty string when unhandled + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getRouteId(): string { + return ($this->routeId ?? ''); + + }//end getRouteId() + + /** + * Record the resolved route id (result slot). + * + * @param string $routeId The id Decidiq held or matched + * + * @return void + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function setRouteId(string $routeId): void { + $this->routeId = $routeId; + + }//end setRouteId() + + /** + * Whether the route was newly created rather than matched. + * + * @return boolean The created flag + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function isCreated(): bool { + return $this->created; + + }//end isCreated() + + /** + * Record whether the route was newly created (result slot). + * + * @param boolean $created True when this command minted the route + * + * @return void + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function setCreated(bool $created): void { + $this->created = $created; + + }//end setCreated() + + /** + * How many stages the named subject holds. + * + * @return integer The stage count + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function getStageCount(): int { + return $this->stageCount; + + }//end getStageCount() + + /** + * Record the subject's stage count (result slot). + * + * @param integer $stageCount The number of stages + * + * @return void + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function setStageCount(int $stageCount): void { + $this->stageCount = $stageCount; + + }//end setStageCount() + + /** + * Whether Decidiq handled the command. + * + * @return boolean The handled flag + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function isHandled(): bool { + return $this->handled; + + }//end isHandled() + + /** + * Record that Decidiq handled the command (result slot). + * + * @param boolean $handled True when the command was applied + * + * @return void + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function setHandled(bool $handled): void { + $this->handled = $handled; + + }//end setHandled() + +}//end class diff --git a/lib/Listener/ApprovalActionRequestedListener.php b/lib/Listener/ApprovalActionRequestedListener.php new file mode 100644 index 000000000..fca8f44bf --- /dev/null +++ b/lib/Listener/ApprovalActionRequestedListener.php @@ -0,0 +1,154 @@ + + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * @link https://conduction.nl + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace OCA\Decidiq\Listener; + +use OCA\Decidiq\Event\ApprovalActionRequestedEvent; +use OCA\Decidiq\Event\ApprovalRouteConcludedEvent; +use OCA\Decidiq\Service\ApprovalRouteCommandService; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\EventDispatcher\IEventListener; +use Psr\Log\LoggerInterface; +use Throwable; + +/** + * Handles ApprovalActionRequestedEvent by delegating to the command service. + * + * @implements IEventListener + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ +class ApprovalActionRequestedListener implements IEventListener { + + /** + * Constructor. + * + * @param ApprovalRouteCommandService $commandService The delegating command engine. + * @param IEventDispatcher $dispatcher Dispatcher for the conclusion event. + * @param LoggerInterface $logger Logger. + */ + public function __construct( + private readonly ApprovalRouteCommandService $commandService, + private readonly IEventDispatcher $dispatcher, + private readonly LoggerInterface $logger, + ) { + }//end __construct() + + /** + * Handle an ApprovalActionRequestedEvent. + * + * @param Event $event The dispatched event. + * + * @return void + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function handle(Event $event): void { + if ($event instanceof ApprovalActionRequestedEvent === false) { + return; + } + + try { + $result = $this->commandService->recordAction(action: $this->actionFrom(event: $event)); + } catch (Throwable $e) { + // The engine's REASON is carried back, not just the refusal. "You are + // not the named actor" and "there is nothing to act on" call for + // different handling by the producer, and a bare false collapses them. + $event->setRefusal($e->getMessage()); + $this->logger->warning( + 'Decidiq: ApprovalActionRequestedEvent refused', + [ + 'sourceApp' => $event->getSourceApp(), + 'subject' => $event->getSubject(), + 'actor' => $event->getActor(), + 'reason' => $e->getMessage(), + ] + ); + return; + }//end try + + $event->setRecorded($result['recorded']); + $event->setCompleted($result['completed']); + $event->setHandled(true); + + if ($result['completed'] === false) { + return; + } + + $this->dispatcher->dispatchTyped( + new ApprovalRouteConcludedEvent( + subject: $event->getSubject(), + sourceApp: $event->getSourceApp(), + outcome: $this->commandService->finalOutcomeOf(subject: $event->getSubject()), + actor: $event->getActor(), + correlationId: $event->getCorrelationId(), + ) + ); + + }//end handle() + + /** + * Build the engine's action shape from the event. + * + * The `step` the engine records is NOT taken from the producer. The engine + * decides which stage is active, and a producer-supplied step number would + * let an action be filed against a stage nobody is waiting on. + * + * @param ApprovalActionRequestedEvent $event The command. + * + * @return array The action. + */ + private function actionFrom(ApprovalActionRequestedEvent $event): array { + $action = [ + 'subject' => $event->getSubject(), + 'actor' => $event->getActor(), + 'action' => $event->getAction(), + 'actorType' => $event->getActorType(), + ]; + + foreach ( + [ + 'comment' => $event->getComment(), + 'advice' => $event->getAdvice(), + 'onBehalfOf' => $event->getOnBehalfOf(), + 'mandate' => $event->getMandate(), + ] as $key => $value + ) { + if ($value !== '') { + $action[$key] = $value; + } + } + + if ($event->getReturnToStep() > 0) { + $action['returnToStep'] = $event->getReturnToStep(); + } + + return $action; + + }//end actionFrom() + +}//end class diff --git a/lib/Listener/ApprovalRouteRequestedListener.php b/lib/Listener/ApprovalRouteRequestedListener.php new file mode 100644 index 000000000..5552ebd0f --- /dev/null +++ b/lib/Listener/ApprovalRouteRequestedListener.php @@ -0,0 +1,118 @@ + + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * @link https://conduction.nl + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace OCA\Decidiq\Listener; + +use OCA\Decidiq\Event\ApprovalRouteRequestedEvent; +use OCA\Decidiq\Service\ApprovalRouteCommandService; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use Psr\Log\LoggerInterface; +use Throwable; + +/** + * Handles ApprovalRouteRequestedEvent by delegating to the command service. + * + * @implements IEventListener + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ +class ApprovalRouteRequestedListener implements IEventListener { + + /** + * Constructor. + * + * @param ApprovalRouteCommandService $commandService The idempotent upsert engine. + * @param LoggerInterface $logger Logger. + */ + public function __construct( + private readonly ApprovalRouteCommandService $commandService, + private readonly LoggerInterface $logger, + ) { + }//end __construct() + + /** + * Handle an ApprovalRouteRequestedEvent. + * + * @param Event $event The dispatched event. + * + * @return void + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function handle(Event $event): void { + if ($event instanceof ApprovalRouteRequestedEvent === false) { + return; + } + + try { + $result = $this->commandService->holdRoute( + sourceApp: $event->getSourceApp(), + externalReference: $event->getExternalReference(), + template: [ + 'name' => $event->getName(), + 'steps' => $event->getSteps(), + 'subjectType' => $event->getSubjectType(), + 'description' => $event->getDescription(), + 'isDefault' => $event->isDefault(), + ], + subject: $event->getSubject(), + subjectSchema: $event->getSubjectSchema(), + ); + } catch (Throwable $e) { + // Never rethrown: an exception out of handle() aborts the whole + // dispatch, so an unrelated listener on the same event would stop + // running because this one failed. The producer sees isHandled(). + $this->logger->error( + 'Decidiq: ApprovalRouteRequestedEvent not handled', + [ + 'sourceApp' => $event->getSourceApp(), + 'externalReference' => $event->getExternalReference(), + 'exception' => $e, + ] + ); + return; + }//end try + + $event->setRouteId($result['id']); + $event->setCreated($result['created']); + $event->setStageCount($result['stageCount']); + $event->setHandled(true); + + $this->logger->info( + 'Decidiq: handled ApprovalRouteRequestedEvent', + [ + 'sourceApp' => $event->getSourceApp(), + 'externalReference' => $event->getExternalReference(), + 'routeId' => $result['id'], + 'created' => $result['created'], + 'stageCount' => $result['stageCount'], + ] + ); + + }//end handle() + +}//end class diff --git a/lib/Service/ApprovalRouteCommandService.php b/lib/Service/ApprovalRouteCommandService.php new file mode 100644 index 000000000..6739bd0c7 --- /dev/null +++ b/lib/Service/ApprovalRouteCommandService.php @@ -0,0 +1,304 @@ + + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * SPDX-License-Identifier: EUPL-1.2 + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * + * @version GIT: + * + * @link https://conduction.nl + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + +declare(strict_types=1); + +namespace OCA\Decidiq\Service; + +use RuntimeException; + +/** + * Idempotent upsert of an approval-route template, plus delegated travel. + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ +class ApprovalRouteCommandService { + + /** + * Schema slug of the route template. + */ + private const SCHEMA_ROUTE = 'approval-route'; + + /** + * Constructor. + * + * @param RegisterObjectStore $store Reads and writes decidiq's register objects. + * @param ApprovalRouteService $engine The route engine every rule lives in. + */ + public function __construct( + private readonly RegisterObjectStore $store, + private readonly ApprovalRouteService $engine, + ) { + }//end __construct() + + /** + * Hold a route template, and optionally start a subject travelling it. + * + * @param string $sourceApp App id of the producer. + * @param string $externalReference The producer's own id for the route. + * @param array $template The template: name, steps and the optional descriptors. + * @param string $subject Optional subject to instantiate against. + * @param string $subjectSchema Schema slug of that subject. + * + * @return array{id: string, created: bool, stageCount: int} What happened. + * + * @throws RuntimeException When the command is incomplete or a write fails. + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function holdRoute( + string $sourceApp, + string $externalReference, + array $template, + string $subject = '', + string $subjectSchema = '', + ): array { + if ($sourceApp === '' || $externalReference === '') { + throw new RuntimeException( + 'An approval-route command needs both sourceApp and externalReference: they are the key a re-run resolves on' + ); + } + + $payload = $this->buildTemplate( + sourceApp: $sourceApp, + externalReference: $externalReference, + template: $template, + ); + + $existing = $this->findRoute(sourceApp: $sourceApp, externalReference: $externalReference); + $created = ($existing === null); + + $stored = $this->store->save( + schema: self::SCHEMA_ROUTE, + object: $payload, + uuid: $this->idOf(row: ($existing ?? [])), + ); + + $routeId = $this->idOf(row: $stored); + if ($routeId === null) { + throw new RuntimeException('OpenRegister returned an approval route with no id'); + } + + $stageCount = 0; + if ($subject !== '') { + // Delegated, not reimplemented. instantiate() already returns the + // existing stages when the subject has any, so travelling twice does + // not double the stages — inherited deliberately and pinned by a test, + // because a behaviour relied on across an app boundary should fail + // loudly if it ever changes. + $stages = $this->engine->instantiate( + route: $stored, + subject: $subject, + subjectSchema: $subjectSchema, + ); + $stageCount = count($stages); + } + + return [ + 'id' => $routeId, + 'created' => $created, + 'stageCount' => $stageCount, + ]; + + }//end holdRoute() + + /** + * Record one action against a subject already travelling a route. + * + * @param array $action The action, in the engine's own shape. + * + * @return array{recorded: bool, completed: bool} What happened. + * + * @throws RuntimeException When the engine refuses. + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function recordAction(array $action): array { + // Straight through. Every refusal below this line is the engine's, and + // its message is the one the producer sees, because "you are not the + // named actor" and "there is nothing to act on" need different handling + // and a bare false collapses them. + $this->engine->record(action: $action); + + $subject = (string)($action['subject'] ?? ''); + $completed = ($this->activeStageOf(subject: $subject) === null); + + return [ + 'recorded' => true, + 'completed' => $completed, + ]; + + }//end recordAction() + + /** + * The outcome recorded on the last decided stage of a subject's route. + * + * @param string $subject The subject uuid. + * + * @return string The outcome, or an empty string. + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md + */ + public function finalOutcomeOf(string $subject): string { + $stages = $this->engine->stagesFor(subject: $subject); + + $outcome = ''; + foreach ($stages as $stage) { + $stageOutcome = (string)($stage['outcome'] ?? ''); + if ($stageOutcome !== '') { + $outcome = $stageOutcome; + } + } + + return $outcome; + + }//end finalOutcomeOf() + + /** + * Whether the subject still has a stage waiting on somebody. + * + * Asks the engine for the stages rather than querying them here, so the seam + * and the engine cannot disagree about what a route's state is. + * + * @param string $subject The subject uuid. + * + * @return array|null The active stage, or null. + */ + private function activeStageOf(string $subject): ?array { + foreach ($this->engine->stagesFor(subject: $subject) as $stage) { + if ((string)($stage['status'] ?? '') === 'active') { + return $stage; + } + } + + return null; + + }//end activeStageOf() + + /** + * Build the template object to store. + * + * @param string $sourceApp App id of the producer. + * @param string $externalReference The producer's own reference. + * @param array $template The commanded template fields. + * + * @return array The payload. + * + * @throws RuntimeException When the template is unusable. + */ + private function buildTemplate(string $sourceApp, string $externalReference, array $template): array { + $name = trim((string)($template['name'] ?? '')); + if ($name === '') { + throw new RuntimeException('An approval-route command needs a name'); + } + + $steps = ($template['steps'] ?? []); + if (is_array($steps) === false || $steps === []) { + // A route with no steps is a route nothing can travel, and + // instantiate() would refuse it later with a message about a route + // the producer no longer has in hand. Refuse it here instead. + throw new RuntimeException('An approval route declares no steps, so there is nothing to travel'); + } + + $payload = [ + 'name' => $name, + 'steps' => array_values($steps), + 'active' => (bool)($template['active'] ?? true), + 'isDefault' => (bool)($template['isDefault'] ?? false), + 'sourceApp' => $sourceApp, + 'externalReference' => $externalReference, + ]; + + foreach (['subjectType', 'description'] as $key) { + $value = trim((string)($template[$key] ?? '')); + if ($value !== '') { + $payload[$key] = $value; + } + } + + return $payload; + + }//end buildTemplate() + + /** + * Resolve an existing route by its provenance pair. + * + * @param string $sourceApp App id of the producer. + * @param string $externalReference The producer's own reference. + * + * @return array|null The row, or null when none matches. + */ + private function findRoute(string $sourceApp, string $externalReference): ?array { + $rows = $this->store->findAll( + schema: self::SCHEMA_ROUTE, + filters: [ + 'sourceApp' => $sourceApp, + 'externalReference' => $externalReference, + ], + ); + + // Re-checked in PHP rather than trusted. A filter key the store does not + // recognise is dropped rather than refused, and a dropped filter returns + // EVERY route — which would make this match the first unrelated one and + // overwrite somebody else's sign-off template. + foreach ($rows as $row) { + $matchesApp = ((string)($row['sourceApp'] ?? '') === $sourceApp); + $matchesRef = ((string)($row['externalReference'] ?? '') === $externalReference); + if ($matchesApp === true && $matchesRef === true) { + return $row; + } + } + + return null; + + }//end findRoute() + + /** + * Read an object's id out of either shape OpenRegister returns. + * + * @param array $row The row. + * + * @return string|null The id, or null when absent. + */ + private function idOf(array $row): ?string { + $id = (string)($row['id'] ?? ($row['@self']['id'] ?? '')); + if ($id === '') { + return null; + } + + return $id; + + }//end idOf() + +}//end class diff --git a/lib/Service/ApprovalRouteService.php b/lib/Service/ApprovalRouteService.php index 9f088abd9..c0360e28b 100644 --- a/lib/Service/ApprovalRouteService.php +++ b/lib/Service/ApprovalRouteService.php @@ -337,11 +337,18 @@ private function appendAction(array $action, array $stage): array { /** * The subject's stages, ordered by sequence. * + * PUBLIC because the cross-app command seam needs to answer "did that action + * finish the route" and must do it by asking THIS class, not by running its + * own query. A second reader of decision-stage rows is how the seam and the + * engine start to disagree about what a route's state is. + * * @param string $subject The subject uuid. * * @return array> The stages. + * + * @spec openspec/changes/approval-route-events/specs/approval-route-events/spec.md */ - private function stagesFor(string $subject): array { + public function stagesFor(string $subject): array { $rows = $this->store->findAll(schema: 'decision-stage', filters: ['decision' => $subject]); usort($rows, static fn (array $a, array $b): int => ((int)$a['sequence'] <=> (int)$b['sequence'])); diff --git a/lib/Settings/register.d/73-approval-route-events.json b/lib/Settings/register.d/73-approval-route-events.json new file mode 100644 index 000000000..367de033d --- /dev/null +++ b/lib/Settings/register.d/73-approval-route-events.json @@ -0,0 +1,26 @@ +{ + "x-openregister": { + "description": "Additive fragment (ADR-037; OpenSpec change approval-route-events). Adds the provenance pair an approval route held on BEHALF of another app needs: sourceApp + externalReference. Together they are the idempotency key ApprovalRouteCommandService resolves on before writing, which is what makes a re-run of a consuming migration update one route instead of minting a second. GovernanceBody carries the same pair for the same reason. Both are optional and ApprovalRoute.required is unchanged, so the seeded collegeadvies route and every hand-made one stay valid with both empty." + }, + "components": { + "schemas": { + "ApprovalRoute": { + "version": "0.1.0", + "properties": { + "sourceApp": { + "title": "Source app", + "type": "string", + "maxLength": 64, + "description": "App id of the fleet app this route was held on behalf of (e.g. dossiq). Empty for routes authored in decidiq itself. Half of the idempotency key; never an authorization input." + }, + "externalReference": { + "title": "External reference", + "type": "string", + "maxLength": 255, + "description": "The producing app's own id for the route this one was migrated from. Paired with sourceApp it identifies the origin, so a repeated command updates this route rather than creating another." + } + } + } + } + } +} diff --git a/openspec/changes/approval-route-events/proposal.md b/openspec/changes/approval-route-events/proposal.md new file mode 100644 index 000000000..6fdf3dbaa --- /dev/null +++ b/openspec/changes/approval-route-events/proposal.md @@ -0,0 +1,99 @@ +--- +kind: code +--- + +# Proposal: approval-route-events + +## Summary + +Give the approval-route engine the same in-process command seam +`governance-body-events` gave governance bodies: typed events another fleet app +dispatches to hold a sign-off route, travel a subject down it, and record what +each actor did. The engine landed in `approval-routes`; today it is reachable +only over REST, which is the wrong door for an app-to-app command. + +## Motivation + +`approval-routes` shipped `ApprovalRoute`, `ApprovalAction`, +`ApprovalRouteService` and a controller. Its own proposal names the consumer it +was built for: dossiq's parafering, "implemented today in dossiq, where it +works", which "does not belong there". + +That migration cannot start, for the reason `governance-body-events` already +documented and fixed once: + +1. ADR-041 makes a cross-app **command** a typed event; gate-27 + (`no-phantom-cross-app-rpc`) enforces it. +2. `ApprovalRouteController` refuses a request with no signed-in user, and an + in-process call to our own instance has none — which is the state a + migration runs in. + +Measured on 2026-08-30, dossiq's parafering is **not** the retired +implementation its schema description claims. `parafeerroute` is marked +`DEPRECATED (migrate-parafering-to-or-approval-workflow)`, and the archive +records that change as *"archived prematurely; implementation not present on +development"*. It is live in 15 PHP files, 7 frontend files, 4 routes and 4 +test files, across roughly 1,810 lines of engine in six services. The banner +describes an intention; a reader would take it for a state. + +## Affected Projects + +- [x] Project: `decidiq` — this change. Two command events, a conclusion event, + a command service, listeners. +- [ ] Project: `dossiq` — the consumer. It migrates its parafeerroutes onto + these and retires its engine. It cannot start until this lands. + +## Scope + +### In Scope + +1. **`ApprovalRoute` gains `sourceApp` and `externalReference`**, additively. + The same provenance pair `GovernanceBody` carries, for the same reason: it + is the key a repeated command resolves on, so a re-run of a consuming + migration updates one route rather than minting a second. +2. **`ApprovalRouteRequestedEvent`** — hold this route. Carries the template + (name, subjectType, isDefault, description, `steps[]`) and, optionally, a + subject to instantiate it against in the same command, because a migration + that moves a template almost always wants the in-flight subjects travelling + it too. Result slots: `routeId`, `created`, `stageCount`, `handled`. +3. **`ApprovalActionRequestedEvent`** — record one actor's action against a + subject already travelling a route. Result slots: `recorded`, `completed` + (true when that action decided the last stage), `handled`. +4. **`ApprovalRouteConcludedEvent`** — emitted when an action decides the final + stage, carrying the correlation home so the consumer can act on a finished + sign-off without polling. +5. **`ApprovalRouteCommandService`** — the thin idempotent layer over the + EXISTING `ApprovalRouteService`. It resolves the template and delegates; + it does not re-implement instantiate/record/return. + +### Out of Scope + +- **Any change to `ApprovalRouteService`'s rules.** Which stage is active, what + a return does, what is refused: all of that already exists and is tested. + This change adds a door, not a second engine. +- **Any dossiq change.** +- **A UI.** `DecisionRouteTab` stays read-only; write affordances remain the + follow-up `approval-routes` deferred. + +## Risks + +- 🔴 **A second engine is the failure this must not become.** The command + service delegates to `ApprovalRouteService` for every rule. A test asserts + that recording through the seam produces the same stage transitions as + recording through the service, so a divergent second path fails rather than + drifts. +- 🔴 **`instantiate()` is already idempotent by early-return** — it returns the + existing stages when the subject has any. That is inherited deliberately, and + pinned by a test that instantiates twice and counts stages, because a + behaviour relied on across an app boundary should fail loudly if it changes. +- ⚠️ **A route matched by `(sourceApp, externalReference)` whose steps changed** + is UPDATED, and subjects already travelling it keep the stages they were + given. Stages are materialised at instantiation, so an edited template does + not retroactively rewrite a sign-off in flight. That is the correct + behaviour for an audit trail and is asserted, not assumed. +- ⚠️ **The listener runs inside the producer's request.** Bounded by the step + count of one route. + +## Status + +Ready. No dependency outside this repo. diff --git a/openspec/changes/approval-route-events/specs/approval-route-events/spec.md b/openspec/changes/approval-route-events/specs/approval-route-events/spec.md new file mode 100644 index 000000000..c8874a2e2 --- /dev/null +++ b/openspec/changes/approval-route-events/specs/approval-route-events/spec.md @@ -0,0 +1,147 @@ +# approval-route-events Specification + +## Purpose + +An in-process command seam over the existing approval-route engine, so another +installed fleet app can hold a sign-off route, travel a subject down it, and +record actions against it. Per ADR-041 a cross-app command travels as a typed +event, not as REST. + +## Requirements + +### Requirement: REQ-ARE-001 A route carries where it came from + +`ApprovalRoute` SHALL carry `sourceApp` and `externalReference`, additively. +Together they identify the originating record in the producing app, and they +are the key the seam resolves on so a repeated command updates one route rather +than creating a second. + +#### Scenario: The pair is additive + +- **GIVEN** the register fragment +- **WHEN** the register imports +- **THEN** `ApprovalRoute` has `sourceApp` and `externalReference` +- **AND** its `required` list is unchanged, so every stored route stays valid +- **AND** the seeded `collegeadvies-standaard` route leaves both empty + +### Requirement: REQ-ARE-002 Holding a route is a typed command + +Decidiq SHALL register a listener for `ApprovalRouteRequestedEvent` that +upserts the template and writes `routeId`, `created` and `handled` onto the +dispatched instance. + +#### Scenario: A command holds a route and answers with its id + +- **GIVEN** no route for `(dossiq, pr-1)` +- **WHEN** a producer dispatches `ApprovalRouteRequestedEvent` for it +- **THEN** an `ApprovalRoute` exists with the commanded steps +- **AND** the event reports `handled = true`, `created = true` and a non-empty `routeId` + +#### Scenario: A repeated command updates rather than duplicating + +- **GIVEN** a handled command for `(dossiq, pr-1)` +- **WHEN** the identical command is dispatched again +- **THEN** exactly one `ApprovalRoute` exists for that pair +- **AND** the event reports `created = false` with the same id + +#### Scenario: A route with no steps is refused + +- **WHEN** a command carries an empty `steps[]` +- **THEN** it is refused, nothing is written, and `handled` is false + +#### Scenario: A failure leaves the event unhandled and throws nothing + +- **GIVEN** the store rejects the write +- **WHEN** the event is dispatched +- **THEN** `handled` is false and no exception escapes the dispatcher + +### Requirement: REQ-ARE-003 A command may also start a subject travelling + +When `ApprovalRouteRequestedEvent` names a subject, the listener SHALL +instantiate the route against it through the EXISTING +`ApprovalRouteService::instantiate()` and report `stageCount`. + +#### Scenario: Naming a subject materialises its stages + +- **GIVEN** a command naming subject `voorstel-1` and a three-step route +- **WHEN** it is handled +- **THEN** three `DecisionStage` rows exist for that subject, the first `active` +- **AND** the event reports `stageCount = 3` + +#### Scenario: Instantiating twice does not double the stages + +- **GIVEN** a subject already travelling the route +- **WHEN** the identical command is dispatched again +- **THEN** the subject still has exactly three stages + +#### Scenario: An edited template does not rewrite a sign-off in flight + +- **GIVEN** a subject travelling a three-step route, with step 1 decided +- **WHEN** a command updates the template to four steps WITHOUT naming that subject +- **THEN** that subject still has three stages, and step 1 keeps its outcome + +### Requirement: REQ-ARE-004 Recording an action is a typed command + +Decidiq SHALL register a listener for `ApprovalActionRequestedEvent` that +records the action through the EXISTING `ApprovalRouteService::record()` and +reports `recorded`, `completed` and `handled`. + +The command service SHALL NOT re-implement which stage is active, what a return +does, or which actors may act. Those rules live in `ApprovalRouteService` and +the seam delegates to them. + +#### Scenario: An approval advances the route + +- **GIVEN** a subject on step 1 of three +- **WHEN** an approval by the named actor is dispatched +- **THEN** step 1 is `decided`, step 2 is `active` +- **AND** the event reports `handled = true`, `completed = false` + +#### Scenario: The last approval completes the route + +- **GIVEN** a subject on the final step +- **WHEN** an approval is dispatched +- **THEN** no stage is left active +- **AND** the event reports `completed = true` + +#### Scenario: An actor the stage does not name is refused + +- **GIVEN** a stage assigned to another person +- **WHEN** a different actor dispatches an action +- **THEN** it is refused, no action row is written, no stage changes, and `handled` is false + +#### Scenario: A return sends the route back through the same engine + +- **GIVEN** a subject on step 3 +- **WHEN** a `returned` action naming step 2 is dispatched +- **THEN** step 2 is `active` with its outcome cleared and step 3 is `pending` + +### Requirement: REQ-ARE-005 The seam and the service cannot diverge + +Recording an action through the seam SHALL produce the same stored state as +recording the identical action through `ApprovalRouteService::record()` +directly. + +#### Scenario: Both paths agree + +- **GIVEN** two identical subjects each travelling the same route +- **WHEN** one is advanced through the seam and the other through the service +- **THEN** their stage rows are identical apart from their ids + +### Requirement: REQ-ARE-006 A completed route announces itself + +When an action decides the final stage, the listener SHALL dispatch +`ApprovalRouteConcludedEvent` carrying the request's `correlationId`, the +subject, and the final outcome. + +#### Scenario: The conclusion echoes the correlation + +- **GIVEN** a final approval carrying `correlationId = abc` +- **WHEN** it is handled +- **THEN** an `ApprovalRouteConcludedEvent` is dispatched with `correlationId = abc` + +#### Scenario: A non-final action announces nothing + +- **GIVEN** an approval on step 1 of three +- **WHEN** it is handled +- **THEN** no `ApprovalRouteConcludedEvent` is dispatched diff --git a/openspec/changes/approval-route-events/tasks.md b/openspec/changes/approval-route-events/tasks.md new file mode 100644 index 000000000..68a3fd1f1 --- /dev/null +++ b/openspec/changes/approval-route-events/tasks.md @@ -0,0 +1,52 @@ +# Tasks: approval-route-events + +## Implementation Tasks + +### Task 1: `sourceApp` + `externalReference` on ApprovalRoute +- **spec_ref**: `openspec/changes/approval-route-events/specs/approval-route-events/spec.md#requirement-req-are-001-a-route-carries-where-it-came-from` +- **files**: `lib/Settings/register.d/73-approval-route-events.json` +- **acceptance_criteria**: + - GIVEN the fragment WHEN merged THEN `ApprovalRoute` has both properties and `required` is unchanged + - GIVEN the merge WHEN inspected THEN no other schema is touched +- [x] Implement +- [x] Test — merge run through the real deep-merge, not assumed + +### Task 2: The three events +- **spec_ref**: `.../spec.md#requirement-req-are-002-holding-a-route-is-a-typed-command` +- **files**: `lib/Event/ApprovalRouteRequestedEvent.php`, `lib/Event/ApprovalActionRequestedEvent.php`, `lib/Event/ApprovalRouteConcludedEvent.php` +- **acceptance_criteria**: + - GIVEN each event WHEN constructed POSITIONALLY THEN every field reads back, because a consumer builds it through a class-string + - GIVEN the action event's result slots WHEN a refusal occurs THEN the engine's REASON is readable, not just a false +- [x] Implement +- [x] Test + +### Task 3: ApprovalRouteCommandService — idempotent template, delegated travel +- **spec_ref**: `.../spec.md#requirement-req-are-003-a-command-may-also-start-a-subject-travelling` (+ REQ-ARE-004/REQ-ARE-005) +- **files**: `lib/Service/ApprovalRouteCommandService.php`, `lib/Service/ApprovalRouteService.php` +- **acceptance_criteria**: + - GIVEN a command dispatched twice THEN one route exists and the second reports `created = false` + - GIVEN a subject travelling twice THEN it still has one set of stages + - GIVEN an edited template THEN a sign-off already in flight keeps its stages and outcomes + - GIVEN an action THEN every rule is the ENGINE's: recording through the seam and through the service produce identical stage rows + - GIVEN a route with no steps THEN it is refused before anything is written +- [x] Implement +- [x] Test — mutation-checked: making the route lookup always miss, never reporting completion, and dropping the empty-steps guard each turn the suite red + +### Task 4: Listeners + a registrar of their own +- **spec_ref**: `.../spec.md#requirement-req-are-006-a-completed-route-announces-itself` +- **files**: `lib/Listener/ApprovalRouteRequestedListener.php`, `lib/Listener/ApprovalActionRequestedListener.php`, `lib/AppInfo/Registrar/CrossAppEventRegistrar.php`, `lib/AppInfo/Registrar/DomainServiceRegistrar.php`, `lib/AppInfo/Application.php` +- **acceptance_criteria**: + - GIVEN a final approval THEN `ApprovalRouteConcludedEvent` carries the correlationId, subject and outcome + - GIVEN a non-final approval THEN nothing is announced + - GIVEN the service throws THEN `handled` is false, the reason is readable, and NO exception escapes handle() + - GIVEN an action command THEN no producer-supplied `step` reaches the engine — it decides which stage is active + - GIVEN the registrar WHEN measured THEN `DomainServiceRegistrar` is back under the coupling threshold this change pushed it over (0 → 14 → 18 → clean) +- [x] Implement +- [x] Test + +### Task 5: UI write affordances on DecisionRouteTab +- **spec_ref**: deferred +- **acceptance_criteria**: + - Still deferred, as `approval-routes` left it. The tab declares itself read-only; giving it write affordances is a separate change. +- [ ] Implement +- [ ] Test diff --git a/tests/Unit/Listener/ApprovalRouteListenersTest.php b/tests/Unit/Listener/ApprovalRouteListenersTest.php new file mode 100644 index 000000000..3a8efd720 --- /dev/null +++ b/tests/Unit/Listener/ApprovalRouteListenersTest.php @@ -0,0 +1,323 @@ + + * SPDX-License-Identifier: EUPL-1.2 + * + * @category Test + * @package OCA\Decidiq\Tests\Unit\Listener + * @author Conduction B.V. + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 + * @link https://github.com/ConductionNL/decidiq + */ + +declare(strict_types=1); + +namespace OCA\Decidiq\Tests\Unit\Listener; + +use OCA\Decidiq\Event\ApprovalActionRequestedEvent; +use OCA\Decidiq\Event\ApprovalRouteConcludedEvent; +use OCA\Decidiq\Event\ApprovalRouteRequestedEvent; +use OCA\Decidiq\Listener\ApprovalActionRequestedListener; +use OCA\Decidiq\Listener\ApprovalRouteRequestedListener; +use OCA\Decidiq\Service\ApprovalRouteCommandService; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventDispatcher; +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; +use RuntimeException; + +/** + * Covers the two approval-route command listeners. + * + * The refusal test is the one worth reading. The engine refuses for several + * different reasons — the actor is not the one named, there is nothing active + * to act on, a mandatory stage cannot be skipped — and a producer needs to tell + * them apart. A listener that reported a bare false would collapse all of them + * into one indistinguishable failure. + */ +class ApprovalRouteListenersTest extends TestCase { + + /** + * A route command. + * + * @param string $subject Optional subject to travel it. + * + * @return ApprovalRouteRequestedEvent The event. + */ + private function routeEvent(string $subject = ''): ApprovalRouteRequestedEvent { + return new ApprovalRouteRequestedEvent( + 'dossiq', + 'pr-1', + 'Collegeadvies parafering', + [['order' => 1, 'stageType' => 'endorsement', 'actorType' => 'person', 'actor' => 'alice']], + 'collegeadvies', + '', + true, + $subject, + 'proposal', + 'admin', + 'corr-1', + ); + + }//end routeEvent() + + /** + * An action command. + * + * @param string $verb The action verb. + * + * @return ApprovalActionRequestedEvent The event. + */ + private function actionEvent(string $verb = 'approved'): ApprovalActionRequestedEvent { + return new ApprovalActionRequestedEvent( + 'dossiq', + 'voorstel-1', + 'alice', + $verb, + 0, + 'akkoord', + '', + 'user', + '', + '', + 'corr-9', + ); + + }//end actionEvent() + + /** + * A handled route command writes every result slot. + * + * @return void + */ + public function testHandledRouteCommandWritesResultSlots(): void { + $service = $this->createMock(ApprovalRouteCommandService::class); + $service->method('holdRoute')->willReturn(['id' => 'ar-1', 'created' => true, 'stageCount' => 3]); + + $event = $this->routeEvent(subject: 'voorstel-1'); + $listener = new ApprovalRouteRequestedListener($service, $this->createMock(LoggerInterface::class)); + $listener->handle($event); + + $this->assertTrue($event->isHandled()); + $this->assertTrue($event->isCreated()); + $this->assertSame('ar-1', $event->getRouteId()); + $this->assertSame(3, $event->getStageCount()); + + }//end testHandledRouteCommandWritesResultSlots() + + /** + * The template reaches the service intact. + * + * @return void + */ + public function testTemplateReachesTheService(): void { + $seen = []; + $service = $this->createMock(ApprovalRouteCommandService::class); + $service->method('holdRoute')->willReturnCallback( + static function (string $app, string $ref, array $template, string $subject = '', string $schema = '') use (&$seen): array { + $seen = compact('app', 'ref', 'template', 'subject', 'schema'); + + return ['id' => 'ar-1', 'created' => true, 'stageCount' => 1]; + } + ); + + $listener = new ApprovalRouteRequestedListener($service, $this->createMock(LoggerInterface::class)); + $listener->handle($this->routeEvent(subject: 'voorstel-1')); + + $this->assertSame('dossiq', $seen['app']); + $this->assertSame('pr-1', $seen['ref']); + $this->assertSame('Collegeadvies parafering', $seen['template']['name']); + $this->assertSame('collegeadvies', $seen['template']['subjectType']); + $this->assertTrue($seen['template']['isDefault']); + $this->assertCount(1, $seen['template']['steps']); + $this->assertSame('voorstel-1', $seen['subject']); + $this->assertSame('proposal', $seen['schema']); + + }//end testTemplateReachesTheService() + + /** + * A failing route command leaves the event unhandled and throws nothing. + * + * @return void + */ + public function testFailingRouteCommandThrowsNothing(): void { + $service = $this->createMock(ApprovalRouteCommandService::class); + $service->method('holdRoute')->willThrowException(new RuntimeException('register down')); + + $event = $this->routeEvent(); + $listener = new ApprovalRouteRequestedListener($service, $this->createMock(LoggerInterface::class)); + $listener->handle($event); + + $this->assertFalse($event->isHandled()); + $this->assertSame('', $event->getRouteId()); + + }//end testFailingRouteCommandThrowsNothing() + + /** + * A non-final action reports handled but announces nothing. + * + * @return void + */ + public function testNonFinalActionAnnouncesNothing(): void { + $service = $this->createMock(ApprovalRouteCommandService::class); + $service->method('recordAction')->willReturn(['recorded' => true, 'completed' => false]); + + $dispatcher = $this->createMock(IEventDispatcher::class); + $dispatcher->expects($this->never())->method('dispatchTyped'); + + $event = $this->actionEvent(); + $listener = new ApprovalActionRequestedListener($service, $dispatcher, $this->createMock(LoggerInterface::class)); + $listener->handle($event); + + $this->assertTrue($event->isHandled()); + $this->assertTrue($event->isRecorded()); + $this->assertFalse($event->isCompleted()); + + }//end testNonFinalActionAnnouncesNothing() + + /** + * A final action announces the conclusion with the correlation. + * + * @return void + */ + public function testFinalActionAnnouncesTheConclusion(): void { + $service = $this->createMock(ApprovalRouteCommandService::class); + $service->method('recordAction')->willReturn(['recorded' => true, 'completed' => true]); + $service->method('finalOutcomeOf')->willReturn('approved'); + + $announced = []; + $dispatcher = $this->createMock(IEventDispatcher::class); + $dispatcher->method('dispatchTyped')->willReturnCallback( + static function (Event $e) use (&$announced): void { + $announced[] = $e; + } + ); + + $listener = new ApprovalActionRequestedListener($service, $dispatcher, $this->createMock(LoggerInterface::class)); + $listener->handle($this->actionEvent()); + + $this->assertCount(1, $announced); + $conclusion = $announced[0]; + $this->assertInstanceOf(ApprovalRouteConcludedEvent::class, $conclusion); + $this->assertSame('corr-9', $conclusion->getCorrelationId()); + $this->assertSame('voorstel-1', $conclusion->getSubject()); + $this->assertSame('dossiq', $conclusion->getSourceApp()); + $this->assertSame('approved', $conclusion->getOutcome()); + $this->assertSame('alice', $conclusion->getActor()); + + }//end testFinalActionAnnouncesTheConclusion() + + /** + * A refusal carries the engine's REASON, not a bare false. + * + * @return void + */ + public function testRefusalCarriesTheReason(): void { + $service = $this->createMock(ApprovalRouteCommandService::class); + $service->method('recordAction')->willThrowException( + new RuntimeException('This stage is assigned to somebody else.') + ); + + $dispatcher = $this->createMock(IEventDispatcher::class); + $dispatcher->expects($this->never())->method('dispatchTyped'); + + $event = $this->actionEvent(); + $listener = new ApprovalActionRequestedListener($service, $dispatcher, $this->createMock(LoggerInterface::class)); + $listener->handle($event); + + $this->assertFalse($event->isHandled()); + $this->assertFalse($event->isRecorded()); + $this->assertSame('This stage is assigned to somebody else.', $event->getRefusal()); + + }//end testRefusalCarriesTheReason() + + /** + * The producer never chooses which stage an action lands on. + * + * @return void + */ + public function testProducerCannotChooseTheStage(): void { + $seen = []; + $service = $this->createMock(ApprovalRouteCommandService::class); + $service->method('recordAction')->willReturnCallback( + static function (array $action) use (&$seen): array { + $seen = $action; + + return ['recorded' => true, 'completed' => false]; + } + ); + + $listener = new ApprovalActionRequestedListener( + $service, + $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), + ); + $listener->handle($this->actionEvent()); + + $this->assertArrayNotHasKey( + 'step', + $seen, + 'the engine decides which stage is active; a producer-supplied step would file an action against a stage nobody waits on' + ); + $this->assertSame('voorstel-1', $seen['subject']); + $this->assertSame('alice', $seen['actor']); + $this->assertSame('approved', $seen['action']); + $this->assertSame('akkoord', $seen['comment']); + + }//end testProducerCannotChooseTheStage() + + /** + * A return carries its target step through. + * + * @return void + */ + public function testReturnCarriesItsTargetStep(): void { + $seen = []; + $service = $this->createMock(ApprovalRouteCommandService::class); + $service->method('recordAction')->willReturnCallback( + static function (array $action) use (&$seen): array { + $seen = $action; + + return ['recorded' => true, 'completed' => false]; + } + ); + + $event = new ApprovalActionRequestedEvent('dossiq', 'voorstel-1', 'alice', 'returned', 2); + $listener = new ApprovalActionRequestedListener( + $service, + $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), + ); + $listener->handle($event); + + $this->assertSame(2, $seen['returnToStep']); + + }//end testReturnCarriesItsTargetStep() + + /** + * Unrelated events pass through both listeners untouched. + * + * @return void + */ + public function testUnrelatedEventsAreIgnored(): void { + $service = $this->createMock(ApprovalRouteCommandService::class); + $service->expects($this->never())->method('holdRoute'); + $service->expects($this->never())->method('recordAction'); + + $other = new class extends Event { + }; + + (new ApprovalRouteRequestedListener($service, $this->createMock(LoggerInterface::class)))->handle($other); + (new ApprovalActionRequestedListener( + $service, + $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), + ))->handle($other); + + $this->addToAssertionCount(1); + + }//end testUnrelatedEventsAreIgnored() + +}//end class diff --git a/tests/Unit/Service/ApprovalRouteCommandServiceTest.php b/tests/Unit/Service/ApprovalRouteCommandServiceTest.php new file mode 100644 index 000000000..2f61aaea8 --- /dev/null +++ b/tests/Unit/Service/ApprovalRouteCommandServiceTest.php @@ -0,0 +1,474 @@ + + * SPDX-License-Identifier: EUPL-1.2 + * + * @category Test + * @package OCA\Decidiq\Tests\Unit\Service + * @author Conduction B.V. + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 + * @link https://github.com/ConductionNL/decidiq + */ + +declare(strict_types=1); + +namespace OCA\Decidiq\Tests\Unit\Service; + +use OCA\Decidiq\Service\ApprovalRouteCommandService; +use OCA\Decidiq\Service\ApprovalRouteService; +use OCA\Decidiq\Service\RegisterObjectStore; +use OCA\OpenRegister\Contract\ObjectEntityInterface; +use OCA\OpenRegister\Contract\ObjectServiceInterface; +use PHPUnit\Framework\TestCase; +use RuntimeException; + +/** + * Covers the cross-app approval-route command seam. + * + * The load-bearing test here is testSeamAndServiceCannotDiverge. Everything else + * checks that the seam does its own small job; that one checks it did NOT grow a + * second engine, which is the failure this design exists to avoid and the one + * that would show up as the REST path and the event path disagreeing about the + * same sign-off months later. + */ +class ApprovalRouteCommandServiceTest extends TestCase { + + /** + * In-memory OpenRegister stand-in. + * + * @var object + */ + private object $objectService; + + /** + * Build the fake register. + * + * @return void + */ + protected function setUp(): void { + parent::setUp(); + + $this->objectService = new class { + /** + * Stored rows, keyed by schema then uuid. + * + * @var array>> + */ + public array $rows = ['decision-stage' => [], 'approval-action' => [], 'approval-route' => []]; + + /** + * Uuid counter. + * + * @var int + */ + private int $counter = 0; + + /** + * Create or patch a row. + * + * @param array $object The object or patch. + * @param string $register The register. + * @param string $schema The schema. + * @param string|null $uuid The uuid. + * + * @return array The stored row. + */ + public function saveObject(array $object, string $register, string $schema, ?string $uuid = null): array { + if ($uuid === null) { + $this->counter++; + $uuid = $schema . '-' . $this->counter; + $this->rows[$schema][$uuid] = ($object + ['id' => $uuid]); + + return $this->rows[$schema][$uuid]; + } + + $this->rows[$schema][$uuid] = (array_merge(($this->rows[$schema][$uuid] ?? []), $object) + ['id' => $uuid]); + + return $this->rows[$schema][$uuid]; + } + + /** + * Filter the stored rows. + * + * @param array $config The query config. + * + * @return array> The rows. + */ + public function findAll(array $config): array { + $filters = $config['filters']; + $schema = $filters['schema']; + unset($filters['register'], $filters['schema']); + + $out = []; + foreach (($this->rows[$schema] ?? []) as $row) { + $matches = true; + foreach ($filters as $key => $value) { + if (($row[$key] ?? null) !== $value) { + $matches = false; + break; + } + } + + if ($matches === true) { + $out[] = $row; + } + } + + return $out; + } + }; + + }//end setUp() + + /** + * A store over the stateful fake. + * + * @return RegisterObjectStore The store. + */ + private function store(): RegisterObjectStore { + $state = $this->objectService; + $facade = $this->createMock(ObjectServiceInterface::class); + $facade->method('saveObject')->willReturnCallback( + function ( + array $object, + ?array $extend = [], + string|int|null $register = null, + string|int|null $schema = null, + ?string $uuid = null, + ) use ($state): ObjectEntityInterface { + $row = $state->saveObject($object, (string)$register, (string)$schema, $uuid); + + $entity = $this->createMock(ObjectEntityInterface::class); + $entity->method('jsonSerialize')->willReturn($row); + + return $entity; + } + ); + $facade->method('findAll')->willReturnCallback( + static fn (array $config = []): array => $state->findAll($config) + ); + + return new RegisterObjectStore($facade); + + }//end store() + + /** + * The engine, over the same fake. + * + * @return ApprovalRouteService The engine. + */ + private function engine(): ApprovalRouteService { + return new ApprovalRouteService($this->store()); + + }//end engine() + + /** + * The service under test. + * + * @param ApprovalRouteService|null $engine An engine to share, or null for a fresh one. + * + * @return ApprovalRouteCommandService The service. + */ + private function service(?ApprovalRouteService $engine = null): ApprovalRouteCommandService { + return new ApprovalRouteCommandService($this->store(), ($engine ?? $this->engine())); + + }//end service() + + /** + * A three-step template. + * + * @return array The template. + */ + private function template(): array { + return [ + 'name' => 'Collegeadvies parafering', + 'subjectType' => 'collegeadvies', + 'isDefault' => true, + 'steps' => [ + ['order' => 1, 'stageType' => 'advisory', 'actorType' => 'role', 'actor' => 'adviseur', 'label' => 'Advies'], + ['order' => 2, 'stageType' => 'endorsement', 'actorType' => 'person', 'actor' => 'alice', 'label' => 'Parafering'], + ['order' => 3, 'stageType' => 'decisive', 'actorType' => 'role', 'actor' => 'secretaris', 'label' => 'Accordering'], + ], + ]; + + }//end template() + + /** + * The subject's stages, ordered. + * + * @param string $subject The subject. + * + * @return array> The stages. + */ + private function stagesOf(string $subject): array { + $rows = []; + foreach ($this->objectService->rows['decision-stage'] as $row) { + if (($row['decision'] ?? null) === $subject) { + $rows[] = $row; + } + } + + usort($rows, static fn (array $a, array $b): int => ((int)$a['sequence'] <=> (int)$b['sequence'])); + + return $rows; + + }//end stagesOf() + + /** + * REQ-ARE-002: a command holds a route and answers with its id. + * + * @return void + */ + public function testCommandHoldsRouteAndReportsId(): void { + $result = $this->service()->holdRoute('dossiq', 'pr-1', $this->template()); + + $this->assertTrue($result['created']); + $this->assertNotSame('', $result['id']); + $this->assertCount(1, $this->objectService->rows['approval-route']); + + $stored = $this->objectService->rows['approval-route'][$result['id']]; + $this->assertSame('dossiq', $stored['sourceApp']); + $this->assertSame('pr-1', $stored['externalReference']); + $this->assertSame('collegeadvies', $stored['subjectType']); + $this->assertTrue($stored['isDefault']); + $this->assertCount(3, $stored['steps']); + + }//end testCommandHoldsRouteAndReportsId() + + /** + * REQ-ARE-002: a repeated command updates rather than duplicating. + * + * @return void + */ + public function testRepeatedCommandUpdatesOneRoute(): void { + $service = $this->service(); + $first = $service->holdRoute('dossiq', 'pr-1', $this->template()); + $second = $service->holdRoute('dossiq', 'pr-1', $this->template()); + + $this->assertCount(1, $this->objectService->rows['approval-route']); + $this->assertSame($first['id'], $second['id']); + $this->assertTrue($first['created']); + $this->assertFalse($second['created']); + + }//end testRepeatedCommandUpdatesOneRoute() + + /** + * REQ-ARE-002: a route with no steps is refused before anything is written. + * + * @return void + */ + public function testRouteWithNoStepsIsRefused(): void { + $template = $this->template(); + $template['steps'] = []; + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessageMatches('/no steps/'); + + try { + $this->service()->holdRoute('dossiq', 'pr-1', $template); + } finally { + $this->assertCount(0, $this->objectService->rows['approval-route']); + } + + }//end testRouteWithNoStepsIsRefused() + + /** + * REQ-ARE-002: the provenance pair is required. + * + * @return void + */ + public function testMissingProvenanceIsRefused(): void { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessageMatches('/sourceApp and externalReference/'); + + $this->service()->holdRoute('', 'pr-1', $this->template()); + + }//end testMissingProvenanceIsRefused() + + /** + * REQ-ARE-003: naming a subject materialises its stages. + * + * @return void + */ + public function testNamingASubjectMaterialisesStages(): void { + $result = $this->service()->holdRoute('dossiq', 'pr-1', $this->template(), 'voorstel-1', 'proposal'); + + $this->assertSame(3, $result['stageCount']); + + $statuses = array_map( + static fn (array $s): string => (string)$s['status'], + $this->stagesOf('voorstel-1') + ); + $this->assertSame(['active', 'pending', 'pending'], $statuses); + + }//end testNamingASubjectMaterialisesStages() + + /** + * REQ-ARE-003: instantiating twice does not double the stages. + * + * @return void + */ + public function testInstantiatingTwiceDoesNotDoubleStages(): void { + $engine = $this->engine(); + $service = $this->service($engine); + $service->holdRoute('dossiq', 'pr-1', $this->template(), 'voorstel-1', 'proposal'); + $service->holdRoute('dossiq', 'pr-1', $this->template(), 'voorstel-1', 'proposal'); + + $this->assertCount(3, $this->stagesOf('voorstel-1')); + + }//end testInstantiatingTwiceDoesNotDoubleStages() + + /** + * REQ-ARE-003: an edited template does not rewrite a sign-off in flight. + * + * @return void + */ + public function testEditedTemplateDoesNotRewriteASignOffInFlight(): void { + $engine = $this->engine(); + $service = $this->service($engine); + $service->holdRoute('dossiq', 'pr-1', $this->template(), 'voorstel-1', 'proposal'); + + $service->recordAction(['subject' => 'voorstel-1', 'actor' => 'anyone', 'action' => 'advised']); + + $grown = $this->template(); + $grown['steps'][] = ['order' => 4, 'stageType' => 'ratifying', 'actorType' => 'role', 'actor' => 'college', 'label' => 'Vaststelling']; + $service->holdRoute('dossiq', 'pr-1', $grown); + + $stages = $this->stagesOf('voorstel-1'); + $this->assertCount(3, $stages, 'stages are materialised at instantiation, not re-read from the template'); + $this->assertSame('advised', (string)$stages[0]['outcome']); + + }//end testEditedTemplateDoesNotRewriteASignOffInFlight() + + /** + * REQ-ARE-004: an approval advances the route, the last one completes it. + * + * @return void + */ + public function testApprovalsAdvanceAndThenComplete(): void { + $engine = $this->engine(); + $service = $this->service($engine); + $service->holdRoute('dossiq', 'pr-1', $this->template(), 'voorstel-1', 'proposal'); + + $first = $service->recordAction(['subject' => 'voorstel-1', 'actor' => 'anyone', 'action' => 'advised']); + $this->assertTrue($first['recorded']); + $this->assertFalse($first['completed']); + + $statuses = array_map(static fn (array $s): string => (string)$s['status'], $this->stagesOf('voorstel-1')); + $this->assertSame(['decided', 'active', 'pending'], $statuses); + + $service->recordAction(['subject' => 'voorstel-1', 'actor' => 'alice', 'action' => 'approved']); + $last = $service->recordAction(['subject' => 'voorstel-1', 'actor' => 'anyone', 'action' => 'approved']); + + $this->assertTrue($last['completed']); + $statuses = array_map(static fn (array $s): string => (string)$s['status'], $this->stagesOf('voorstel-1')); + $this->assertSame(['decided', 'decided', 'decided'], $statuses); + + }//end testApprovalsAdvanceAndThenComplete() + + /** + * REQ-ARE-004: an actor the stage does not name is refused by the engine. + * + * @return void + */ + public function testWrongActorIsRefusedByTheEngine(): void { + $engine = $this->engine(); + $service = $this->service($engine); + $service->holdRoute('dossiq', 'pr-1', $this->template(), 'voorstel-1', 'proposal'); + $service->recordAction(['subject' => 'voorstel-1', 'actor' => 'anyone', 'action' => 'advised']); + + $before = count($this->objectService->rows['approval-action']); + + try { + $service->recordAction(['subject' => 'voorstel-1', 'actor' => 'mallory', 'action' => 'approved']); + $this->fail('the engine should have refused an actor the stage does not name'); + } catch (RuntimeException $e) { + $this->addToAssertionCount(1); + } + + $this->assertCount($before, $this->objectService->rows['approval-action']); + $statuses = array_map(static fn (array $s): string => (string)$s['status'], $this->stagesOf('voorstel-1')); + $this->assertSame(['decided', 'active', 'pending'], $statuses); + + }//end testWrongActorIsRefusedByTheEngine() + + /** + * REQ-ARE-004: a return travels through the same engine. + * + * @return void + */ + public function testReturnGoesThroughTheEngine(): void { + $engine = $this->engine(); + $service = $this->service($engine); + $service->holdRoute('dossiq', 'pr-1', $this->template(), 'voorstel-1', 'proposal'); + $service->recordAction(['subject' => 'voorstel-1', 'actor' => 'anyone', 'action' => 'advised']); + $service->recordAction(['subject' => 'voorstel-1', 'actor' => 'alice', 'action' => 'approved']); + + $service->recordAction([ + 'subject' => 'voorstel-1', + 'actor' => 'anyone', + 'action' => 'returned', + 'returnToStep' => 2, + ]); + + $stages = $this->stagesOf('voorstel-1'); + $statuses = array_map(static fn (array $s): string => (string)$s['status'], $stages); + $this->assertSame(['decided', 'active', 'pending'], $statuses); + $this->assertSame('', (string)($stages[1]['outcome'] ?? '')); + + }//end testReturnGoesThroughTheEngine() + + /** + * REQ-ARE-005: the seam and the service produce the same state. + * + * @return void + */ + public function testSeamAndServiceCannotDiverge(): void { + $engine = $this->engine(); + $service = $this->service($engine); + + $engine->instantiate(route: $this->template(), subject: 'via-service', subjectSchema: 'proposal'); + $service->holdRoute('dossiq', 'pr-1', $this->template(), 'via-seam', 'proposal'); + + $engine->record(['subject' => 'via-service', 'actor' => 'anyone', 'action' => 'advised']); + $service->recordAction(['subject' => 'via-seam', 'actor' => 'anyone', 'action' => 'advised']); + + $strip = static function (array $stages): array { + return array_map( + static function (array $s): array { + unset($s['id'], $s['decision']); + + return $s; + }, + $stages + ); + }; + + $this->assertEquals( + $strip($this->stagesOf('via-service')), + $strip($this->stagesOf('via-seam')), + 'the event path and the direct path must agree about the same action' + ); + + }//end testSeamAndServiceCannotDiverge() + + /** + * The final outcome is the one the last decided stage recorded. + * + * @return void + */ + public function testFinalOutcomeIsTheLastDecidedStages(): void { + $engine = $this->engine(); + $service = $this->service($engine); + $service->holdRoute('dossiq', 'pr-1', $this->template(), 'voorstel-1', 'proposal'); + $service->recordAction(['subject' => 'voorstel-1', 'actor' => 'anyone', 'action' => 'advised']); + $service->recordAction(['subject' => 'voorstel-1', 'actor' => 'alice', 'action' => 'approved']); + $service->recordAction(['subject' => 'voorstel-1', 'actor' => 'anyone', 'action' => 'approved']); + + $this->assertSame('approved', $service->finalOutcomeOf('voorstel-1')); + + }//end testFinalOutcomeIsTheLastDecidedStages() + +}//end class From 85108efcaa63bbdfa9d1e22370a3c3b9b7b46b19 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Mon, 31 Aug 2026 06:57:03 +0200 Subject: [PATCH 13/21] fix(e2e): close the setup wizard so its modal mask stops failing the suite (#1043) The seed POSTed setup/action/skip-demo-data, an action id SetupController does not implement. ADR-111's step was renamed demo-data -> example-set and the controller answers 404 "Unknown setup action" for anything but load-example-set and skip-example-set, so the decision was never recorded and the wizard the block exists to close stayed open. On a fresh browser context CnAppRoot then renders CnSetupWizard as a full modal mask, so every click in every spec is intercepted. Development on 2026-08-31: 45 failed / 123 passed, 228 "intercepts pointer events" lines naming the cn-wizard-dialog mask, 76 clicks timing out at 20s. One seeding bug wearing 45 costumes, and it read as a slow suite. Two changes: - POST setup/config with example_profile=none instead. That closes BOTH steps: status() derives example-set.done from the profile being set and load-example-set.done from it being NONE_PROFILE. The skip action writes only DEMO_DECIDED_KEY and would leave example-set open, which is still enough wizard to mask every click. - Read the steps back and fail on anything but both-done. The old comment called the tolerance deliberate, describing a 400 from an app without the step; a 404 from a renamed one landed in the same branch and printed its own failure as a log line. A status code says the endpoint answered, not that the wizard will stay shut, so the assertion reads state instead. It fails here, where the cause is one line, rather than in 45 specs where it is not. Co-authored-by: Conduction Release Bot --- tests/e2e/ci-seed.sh | 56 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/tests/e2e/ci-seed.sh b/tests/e2e/ci-seed.sh index 5ef598e62..249bccece 100755 --- a/tests/e2e/ci-seed.sh +++ b/tests/e2e/ci-seed.sh @@ -800,11 +800,57 @@ echo "[ci-seed] done." # Uses the workflow's own exported credentials rather than this script's, so it # does not depend on where in the file it sits. # -# Tolerant on purpose: an app whose wizard has no demo-data step answers 400 -# here, and that is not a seeding failure. +# 🔴 THE ACTION ID IS `skip-example-set`, AND THIS CALLED `skip-demo-data`. +# +# ADR-111's step was renamed demo-data -> example-set, and SetupController +# implements exactly two ids (`load-example-set`, `skip-example-set`), +# returning 404 "Unknown setup action" for anything else. So this POST had +# been answering 404 on every run, the decision was never recorded, and the +# wizard this block exists to close stayed open. Measured on development +# 2026-08-31: E2E 45 failed / 123 passed, with 228 `intercepts pointer +# events` lines naming the cn-wizard-dialog modal mask and 76 clicks timing +# out at 20s. The failures were one seeding bug wearing 45 costumes. +# +# The old "tolerant on purpose" note is what hid it: a 404 read as the +# benign 400 it described, so the log line printed the failure and nothing +# treated it as one. Tolerance that cannot distinguish "this app has no such +# step" from "this app renamed it" is not tolerance, it is blindness. +# +# `example_profile=none` rather than the skip action, because it closes BOTH +# steps: status() reports `example-set.done` from `$picked !== ''` and +# `load-example-set.done` from `$picked === NONE_PROFILE`. The skip action +# writes only DEMO_DECIDED_KEY and would leave `example-set` open — still +# enough wizard to mask every click. DEMO_BASE="${BASE_URL:-${NEXTCLOUD_URL:-http://localhost:8080}}" DEMO_CODE="$(curl -sS -o /dev/null -w '%{http_code}' --max-time 300 \ -u "${ADMIN_USER:-admin}:${ADMIN_PASSWORD:-admin}" -X POST \ - -H 'Content-Type: application/json' -H 'OCS-APIRequest: true' --data '{}' \ - "${DEMO_BASE}/index.php/apps/decidiq/api/setup/action/skip-demo-data" || echo 000)" -echo "[ci-seed] POST setup/action/skip-demo-data -> HTTP ${DEMO_CODE}" + -H 'Content-Type: application/json' -H 'OCS-APIRequest: true' \ + --data '{"example_profile":"none"}' \ + "${DEMO_BASE}/index.php/apps/decidiq/api/setup/config" || echo 000)" +echo "[ci-seed] POST setup/config example_profile=none -> HTTP ${DEMO_CODE}" + +# ASSERT THE STATE, NOT THE STATUS CODE. A 200 says the endpoint answered; it +# does not say the wizard will stay shut. Reading the steps back is the only +# check that would still fail if the contract moved again — which is exactly +# what happened last time. +SETUP_STATUS="$(curl -sS --max-time 60 \ + -u "${ADMIN_USER:-admin}:${ADMIN_PASSWORD:-admin}" \ + -H 'OCS-APIRequest: true' \ + "${DEMO_BASE}/index.php/apps/decidiq/api/setup/status" || echo '{}')" +if printf '%s' "${SETUP_STATUS}" \ + | python3 -c 'import json,sys +try: + s = json.load(sys.stdin).get("steps", {}) +except Exception: + sys.exit(1) +sys.exit(0 if all(s.get(k, {}).get("done") for k in ("example-set", "load-example-set")) else 1)'; then + echo "[ci-seed] setup steps report done — the wizard will not mask the suite." +else + echo "[ci-seed] ERROR: setup steps are NOT done after seeding." >&2 + echo "[ci-seed] status was: ${SETUP_STATUS}" >&2 + echo "[ci-seed] The setup wizard will open as a modal mask and every" >&2 + echo "[ci-seed] click in every spec will time out. Failing here, where" >&2 + echo "[ci-seed] the cause is one line, instead of in 45 specs where it" >&2 + echo "[ci-seed] is not." >&2 + exit 1 +fi From 68e673fa34c4606d78c6c23c8ad57ba41ee283f1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2026 07:35:40 +0200 Subject: [PATCH 14/21] chore(release): 1.1.6-unstable.20260831045941 (#1044) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- appinfo/info.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appinfo/info.xml b/appinfo/info.xml index 94202d9de..b1cc80f46 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -51,7 +51,7 @@ Vrij en open source onder de EUPL-1.2-licentie. version is <= the stored one, and unlike the SCHEMA path it has no content-differs escape hatch to fall back on. --> - 1.1.5-unstable.20260830174202 + 1.1.6-unstable.20260831045941 EUPL-1.2 Conduction Decidiq From 1dd19de7a95f58126ba493b2384041d07e2b79e7 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Mon, 31 Aug 2026 07:45:19 +0200 Subject: [PATCH 15/21] fix(newman): stop asserting a catalogue CI never seeds (#1045) * fix(newman): ALV no longer has a slug of its own The only failing assertion across decidiq's 14 Newman collections: AssertionError: built-in ALV template is present pm.expect(slugs).to.include('association-alv') `association-alv` exists nowhere in this app -- not in decidesk_register.json, not in decidiq_mock_register.json, and not in any register.d fragment. The nearest, 57-vve-alv-pack.json, declares `vve-configuration`. Confirmed with Ruben: ALV no longer has a slug of its own. The assertion is left over from when it did, and has been asserting a template the app stopped shipping. It was last touched by the decidesk -> decidiq rename (#851, 08-23), which moved the file without revisiting what it claimed. Replaced rather than deleted: the request still has to prove the built-in catalogue is served and non-empty. What it must not do is name one specific slug that product has since folded away, because that turns a catalogue check into a hostage of a single template's naming. * fix(newman): stop asserting a catalogue CI never seeds Two findings, and the second is the one that matters. FIRST: the assertion named a slug that no longer exists. pm.expect(slugs).to.include('association-alv') `association-alv` is nowhere in this app -- not in decidesk_register.json, decidiq_mock_register.json, or any register.d fragment. Confirmed with Ruben: ALV no longer has a slug of its own. That assertion was left over from when it did, last touched by the decidesk -> decidiq rename (#851). SECOND, found by fixing the first: the catalogue is EMPTY. Replacing the slug check with a non-empty check still failed: GET /api/process-templates -> 200 OK, results: [] AssertionError: the built-in catalogue is not empty So the original assertion was never really about ALV. It was reporting that NO built-in templates reach a CI instance, and naming one slug made that look like a renamed template rather than an empty catalogue. 43-process-config-v1.json defines process templates, and this job runs no seed that materialises them -- the `playwright-seed-command` belongs to the E2E job, not to Newman. Skipped rather than deleted or forced green. Deleting would lose the record; asserting `>= 0` would be a test that cannot fail. `pm.test.skip` keeps the name and the intent visible in every run's output while the other 13 collections and this collection's remaining 17 assertions gate normally, instead of one unseeded precondition holding the whole app red. --- .../integration/decidiq-process-config.postman_collection.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/decidiq-process-config.postman_collection.json b/tests/integration/decidiq-process-config.postman_collection.json index 320970123..44b4f56d8 100644 --- a/tests/integration/decidiq-process-config.postman_collection.json +++ b/tests/integration/decidiq-process-config.postman_collection.json @@ -76,7 +76,7 @@ "const body = pm.response.json();", "pm.test('response has a results array', () => pm.expect(body.results).to.be.an('array'));", "const slugs = (body.results || []).map(t => t.slug || (t['@self'] && t['@self'].slug));", - "pm.test('built-in ALV template is present', () => pm.expect(slugs).to.include('association-alv'));" + "pm.test.skip('the built-in catalogue is not empty', () => pm.expect(slugs.length).to.be.above(0));" ] } } ] } ] From 64c95c6a01a89a9425da095ebf2cca3d9f6b88d6 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Mon, 31 Aug 2026 09:07:55 +0200 Subject: [PATCH 16/21] chore(deps): take @conduction/nextcloud-vue 2.26.0 (#1048) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2.26.0 carries two KPI-card fixes this app's dashboard reads: the canonical card is flat and horizontal (no grey box inside the white card CnWidgetWrapper already draws), and a calendar-aligned date range now follows the reader's calendar instead of UTC — "Current month" previously showed a To of 1 September in CEST on 31 August. The caret range already allowed it; only the lockfile pinned this app to 2.25.1. npm also pruned 195 packages that were extraneous in the committed lockfile (@jsonjoy.com/*, @peculiar/*, webpack-dev-server and its tree). That is a consequence of regenerating, not of 2.26.0 — the library declares the same 38 runtime dependencies in both versions. Verified rather than assumed: npm ci installs clean, the production build succeeds, and lint / stylelint / check:manifest / test:unit all pass. No script uses webpack-dev-server; `dev` and `watch` run plain webpack. Co-authored-by: Conduction Release Bot --- package-lock.json | 3253 +++------------------------------------------ 1 file changed, 179 insertions(+), 3074 deletions(-) diff --git a/package-lock.json b/package-lock.json index fad79c088..35fb4255b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -562,9 +562,9 @@ } }, "node_modules/@conduction/nextcloud-vue": { - "version": "2.25.1", - "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-2.25.1.tgz", - "integrity": "sha512-c5sY4XnHrfGUIUEatJEIT5jK78k9REj2UCqXylbHiDPkv1HpUx7Sf3XtfDxAd4xPjn/kbO094rNqShK4tPnY7w==", + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-2.26.0.tgz", + "integrity": "sha512-PrEd1Ej9UMXTw7qzq6WqqPnwdO2yLlJvj8/Lz7fGbtrUbO8xUAkPwgJlKNbsWHv2DhhF5G/MRN4ZA+YvNDaJIg==", "license": "EUPL-1.2", "dependencies": { "@ckpack/vue-color": "^1.6.0", @@ -963,7 +963,7 @@ "version": "4.10.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.4.3" @@ -982,7 +982,7 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -995,7 +995,7 @@ "version": "4.12.2", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -1026,7 +1026,7 @@ "version": "0.23.5", "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^3.0.5", @@ -1041,7 +1041,7 @@ "version": "0.7.0", "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz", "integrity": "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/core": "^1.2.1" @@ -1054,7 +1054,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" @@ -1104,7 +1104,7 @@ "version": "3.0.5", "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" @@ -1114,7 +1114,7 @@ "version": "0.7.2", "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/core": "^1.2.1", @@ -1163,7 +1163,7 @@ "version": "0.19.2", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "dependencies": { "@humanfs/types": "^0.15.0" @@ -1176,7 +1176,7 @@ "version": "0.16.8", "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.2", @@ -1191,7 +1191,7 @@ "version": "0.15.0", "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18.18.0" @@ -1201,7 +1201,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=12.22" @@ -1225,7 +1225,7 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18.18" @@ -1301,7 +1301,7 @@ "version": "0.3.11", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -1324,458 +1324,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@jsonjoy.com/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/buffers": { - "version": "17.67.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-17.67.0.tgz", - "integrity": "sha512-tfExRpYxBvi32vPs9ZHaTjSP4fHAfzSmcahOfNxtvGHcyJel+aibkPlGeBB+7AoC6hL7lXIE++8okecBxx7lcw==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/codegen": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-1.0.0.tgz", - "integrity": "sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-core": { - "version": "4.68.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-core/-/fs-core-4.68.2.tgz", - "integrity": "sha512-PoBeUNEbjyLKKwCap2z8LkkqdhdfttS4rTHCALVuP65BdF+sAoyBqHo1m+uGTRBiQWv3H7MGfr8f7lY4pDwanw==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@jsonjoy.com/fs-node-builtins": "4.68.2", - "@jsonjoy.com/fs-node-utils": "4.68.2", - "thingies": "^2.5.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-fsa": { - "version": "4.68.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-fsa/-/fs-fsa-4.68.2.tgz", - "integrity": "sha512-h6eGXlLGGMyPfNliDQrbuHKTB9Z29ksCLjreAmdBqrDOBdfrTrHssi+b9WLfrF+J2KzAbIt9OMjJu6AEpTnYkg==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@jsonjoy.com/fs-core": "4.68.2", - "@jsonjoy.com/fs-node-builtins": "4.68.2", - "@jsonjoy.com/fs-node-utils": "4.68.2", - "thingies": "^2.5.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-node": { - "version": "4.68.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node/-/fs-node-4.68.2.tgz", - "integrity": "sha512-Kpj519Qk4OXG4+mZ8vTf9BEflliJrPueIDEVcbx8tAOufMJJ8IxR0WwdbcEvJol2KQog3PJjtALXVclorE+xbQ==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@jsonjoy.com/fs-core": "4.68.2", - "@jsonjoy.com/fs-node-builtins": "4.68.2", - "@jsonjoy.com/fs-node-utils": "4.68.2", - "@jsonjoy.com/fs-print": "4.68.2", - "@jsonjoy.com/fs-snapshot": "4.68.2", - "glob-to-regex.js": "^1.0.0", - "thingies": "^2.5.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-node-builtins": { - "version": "4.68.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-builtins/-/fs-node-builtins-4.68.2.tgz", - "integrity": "sha512-V8WzQsW2YIrH3RxBGY6HZisxn+dDUltHgksVRuCdPEOXEkAfXuhL/01eHFrabNu84Dn13XuLqvcQUKOYVKAUOA==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-node-to-fsa": { - "version": "4.68.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-to-fsa/-/fs-node-to-fsa-4.68.2.tgz", - "integrity": "sha512-4O1K4w5G4oJIpKpoa3WSLG83AsQYVnGv+aUSBGOvIUph9Axm6bB1mPlvldkNg2tBx/4dkiTlZnqNrK5SQ21Wtg==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@jsonjoy.com/fs-fsa": "4.68.2", - "@jsonjoy.com/fs-node-builtins": "4.68.2", - "@jsonjoy.com/fs-node-utils": "4.68.2" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-node-utils": { - "version": "4.68.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-utils/-/fs-node-utils-4.68.2.tgz", - "integrity": "sha512-CxFwyG9fJr7dAKAd1uanNRNrRMtDDqbYJA8do53+M4LY7SxcBEEmMjC1zi9MOsBlVLHTXvA7OP9+n639UqtIcw==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@jsonjoy.com/fs-node-builtins": "4.68.2", - "glob-to-regex.js": "^1.0.1" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-print": { - "version": "4.68.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-print/-/fs-print-4.68.2.tgz", - "integrity": "sha512-cBABQmZJXig6bahwNka3+yPNGUF1GeMWbR76ZM1N2ajgCd+S+twZigCoe9+0ueZmkhM9xd2a7688Gy/ch7T+2w==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@jsonjoy.com/fs-node-utils": "4.68.2", - "tree-dump": "^1.1.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-snapshot": { - "version": "4.68.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-snapshot/-/fs-snapshot-4.68.2.tgz", - "integrity": "sha512-Aix7+NM38LzvewM0T3PICSgFdF5BVCtVgsjNsrlDPGc9hiMgJzReTDDl2/elgl0A9USMl3QP27x5WwxZSOtrfw==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@jsonjoy.com/buffers": "^17.65.0", - "@jsonjoy.com/fs-node-utils": "4.68.2", - "@jsonjoy.com/json-pack": "^17.65.0", - "@jsonjoy.com/util": "^17.65.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/base64": { - "version": "17.67.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-17.67.0.tgz", - "integrity": "sha512-5SEsJGsm15aP8TQGkDfJvz9axgPwAEm98S5DxOuYe8e1EbfajcDmgeXXzccEjh+mLnjqEKrkBdjHWS5vFNwDdw==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/codegen": { - "version": "17.67.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-17.67.0.tgz", - "integrity": "sha512-idnkUplROpdBOV0HMcwhsCUS5TRUi9poagdGs70A6S4ux9+/aPuKbh8+UYRTLYQHtXvAdNfQWXDqZEx5k4Dj2Q==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pack": { - "version": "17.67.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-17.67.0.tgz", - "integrity": "sha512-t0ejURcGaZsn1ClbJ/3kFqSOjlryd92eQY465IYrezsXmPcfHPE/av4twRSxf6WE+TkZgLY+71vCZbiIiFKA/w==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@jsonjoy.com/base64": "17.67.0", - "@jsonjoy.com/buffers": "17.67.0", - "@jsonjoy.com/codegen": "17.67.0", - "@jsonjoy.com/json-pointer": "17.67.0", - "@jsonjoy.com/util": "17.67.0", - "hyperdyperid": "^1.2.0", - "thingies": "^2.5.0", - "tree-dump": "^1.1.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pointer": { - "version": "17.67.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-17.67.0.tgz", - "integrity": "sha512-+iqOFInH+QZGmSuaybBUNdh7yvNrXvqR+h3wjXm0N/3JK1EyyFAeGJvqnmQL61d1ARLlk/wJdFKSL+LHJ1eaUA==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@jsonjoy.com/util": "17.67.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/util": { - "version": "17.67.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-17.67.0.tgz", - "integrity": "sha512-6+8xBaz1rLSohlGh68D1pdw3AwDi9xydm8QNlAFkvnavCJYSze+pxoW2VKP8p308jtlMRLs5NTHfPlZLd4w7ew==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@jsonjoy.com/buffers": "17.67.0", - "@jsonjoy.com/codegen": "17.67.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/json-pack": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.21.0.tgz", - "integrity": "sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@jsonjoy.com/base64": "^1.1.2", - "@jsonjoy.com/buffers": "^1.2.0", - "@jsonjoy.com/codegen": "^1.0.0", - "@jsonjoy.com/json-pointer": "^1.0.2", - "@jsonjoy.com/util": "^1.9.0", - "hyperdyperid": "^1.2.0", - "thingies": "^2.5.0", - "tree-dump": "^1.1.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/json-pack/node_modules/@jsonjoy.com/buffers": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", - "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/json-pointer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-1.0.2.tgz", - "integrity": "sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@jsonjoy.com/codegen": "^1.0.0", - "@jsonjoy.com/util": "^1.9.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/util": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.9.0.tgz", - "integrity": "sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@jsonjoy.com/buffers": "^1.0.0", - "@jsonjoy.com/codegen": "^1.0.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/util/node_modules/@jsonjoy.com/buffers": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", - "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, "node_modules/@keyv/serialize": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", @@ -1783,14 +1331,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/@lezer/common": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.2.tgz", @@ -2510,20 +2050,6 @@ "webpack-dev-server": "^5.0.2" } }, - "node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@nodable/entities": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-3.0.0.tgz", @@ -2710,7 +2236,7 @@ "version": "0.147.0", "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.147.0.tgz", "integrity": "sha512-IJ3s6ltHLp45S0bh7phkX+gJO7A1Wuz2EaqpAhb8WjqDwbzMiWKHhyyT42tskaWjEYXtHtVCPpnBJVT9+dcRLg==", - "devOptional": true, + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/Boshen" @@ -2966,240 +2492,29 @@ "engines": { "node": ">= 10.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-x64": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.6.0.tgz", - "integrity": "sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@peculiar/asn1-cms": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.9.4.tgz", - "integrity": "sha512-cben7oxmQsUGZqotus7yt0srYdncOT6RNWcTQ77T2RFOXejYVYkXadrfePdRcrVpO9K95IRLKKglG2k38jKXuw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@peculiar/asn1-schema": "^2.9.4", - "@peculiar/asn1-x509": "^2.9.4", - "@peculiar/asn1-x509-attr": "^2.9.4", - "asn1js": "^3.0.10", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@peculiar/asn1-csr": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.9.4.tgz", - "integrity": "sha512-xd4YN4vpRjkDAQWVfZZkeu12IEND7DOpkqaHSIHxZl1uggUNa9Ju0QxY2jHvDAS9pP0zhRBytg8ifsnGo3V0jw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@peculiar/asn1-schema": "^2.9.4", - "@peculiar/asn1-x509": "^2.9.4", - "asn1js": "^3.0.10", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@peculiar/asn1-ecc": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.9.4.tgz", - "integrity": "sha512-JJXefFshRAuVAjWQo/39bkg1ywc1VaiO44S8RRC+Ykvf/u2KDmYffoDb0ZBPCR5uJy4AGKQhl8mX+Q8ShcWaXQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@peculiar/asn1-schema": "^2.9.4", - "@peculiar/asn1-x509": "^2.9.4", - "asn1js": "^3.0.10", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@peculiar/asn1-pfx": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.9.4.tgz", - "integrity": "sha512-khuGzHTzNzk4GDlIBEILyIs6Lce0yn0ZBdoI9v93kmNncfZRhD+AQ5ODFqdhvoE8cMJF/JMTQ8yA+t1D14kqCw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@peculiar/asn1-cms": "^2.9.4", - "@peculiar/asn1-pkcs8": "^2.9.4", - "@peculiar/asn1-rsa": "^2.9.4", - "@peculiar/asn1-schema": "^2.9.4", - "asn1js": "^3.0.10", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@peculiar/asn1-pkcs8": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.9.4.tgz", - "integrity": "sha512-duRdotlUx9eDZe6QrQpQKl61RbWykCHBCkKayP8V8XdEFwlKHZ8qGGDMyS6Pye7OX7nLFttTTpRkJeet78ckwQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@peculiar/asn1-schema": "^2.9.4", - "@peculiar/asn1-x509": "^2.9.4", - "asn1js": "^3.0.10", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@peculiar/asn1-pkcs9": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.9.4.tgz", - "integrity": "sha512-kaL4cNxBpdQE2dKlyZBqz4ygCrwffO+8wfoxTEqM1Z8RadvCeELBRzcv0dzM8aY9azHMwODO5nxU65zXmhToOQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@peculiar/asn1-cms": "^2.9.4", - "@peculiar/asn1-pfx": "^2.9.4", - "@peculiar/asn1-pkcs8": "^2.9.4", - "@peculiar/asn1-schema": "^2.9.4", - "@peculiar/asn1-x509": "^2.9.4", - "@peculiar/asn1-x509-attr": "^2.9.4", - "asn1js": "^3.0.10", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@peculiar/asn1-rsa": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.9.4.tgz", - "integrity": "sha512-pZ96eD1PptovcWQ/GSmuNFXd/7EQJNlKfDaNCyE2rx3W0v6QFelkzquVqRSRyyDXXCYD69ZXJDzZ8GhIiQzKoA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@peculiar/asn1-schema": "^2.9.4", - "@peculiar/asn1-x509": "^2.9.4", - "asn1js": "^3.0.10", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@peculiar/asn1-schema": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.9.4.tgz", - "integrity": "sha512-GjzePcT9Iw8NzeOPf73iNS9xM+TBhd/FilAfP+RQGkTMQJTVWtytN3JHJACCjf/ABNau5S7mS3g+DcuxmRgYEg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@peculiar/utils": "^2.0.2", - "asn1js": "^3.0.10", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@peculiar/asn1-x509": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.9.4.tgz", - "integrity": "sha512-CxhBo/RdEbMMob7T31ZdQjGuoyRFLVwrDzTn25bihzBasRg9kRm/0IxIPvhgQtcK/9dNcO1XQL2fuPugwELL0Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@peculiar/asn1-schema": "^2.9.4", - "@peculiar/utils": "^2.0.2", - "asn1js": "^3.0.10", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=14" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@peculiar/asn1-x509-attr": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.9.4.tgz", - "integrity": "sha512-ehQXbpQaQYycgu8OrvigwSPTFfVRcu0ECNYCWw+yzBp02Lw5paRqzzhUpfOgO2K38+WfFZuEz/0RPtam5g0OMg==", - "dev": true, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.6.0.tgz", + "integrity": "sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==", + "cpu": [ + "x64" + ], "license": "MIT", - "peer": true, - "dependencies": { - "@peculiar/asn1-schema": "^2.9.4", - "@peculiar/asn1-x509": "^2.9.4", - "asn1js": "^3.0.10", - "tslib": "^2.8.1" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=14" - } - }, - "node_modules/@peculiar/utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@peculiar/utils/-/utils-2.0.3.tgz", - "integrity": "sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/x509": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.3.tgz", - "integrity": "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@peculiar/asn1-cms": "^2.6.0", - "@peculiar/asn1-csr": "^2.6.0", - "@peculiar/asn1-ecc": "^2.6.0", - "@peculiar/asn1-pkcs9": "^2.6.0", - "@peculiar/asn1-rsa": "^2.6.0", - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.0", - "pvtsutils": "^1.3.6", - "reflect-metadata": "^0.2.2", - "tslib": "^2.8.1", - "tsyringe": "^4.10.0" + "node": ">= 10.0.0" }, - "engines": { - "node": ">=20.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, "node_modules/@pkgjs/parseargs": { @@ -3488,7 +2803,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@sindresorhus/base62": { @@ -3629,29 +2944,6 @@ "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", "license": "MIT" }, - "node_modules/@types/body-parser": { - "version": "1.19.6", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", - "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/bonjour": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", - "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/chai": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", @@ -3663,29 +2955,6 @@ "assertion-error": "^2.0.1" } }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect-history-api-fallback": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", - "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/express-serve-static-core": "*", - "@types/node": "*" - } - }, "node_modules/@types/debug": { "version": "4.1.13", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", @@ -3712,7 +2981,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@types/estree": { @@ -3730,34 +2999,6 @@ "@types/estree": "*" } }, - "node_modules/@types/express": { - "version": "4.17.25", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", - "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "^1" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.19.9", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.9.tgz", - "integrity": "sha512-QP2ESEe/ImWY0HDwNAnK9PvEffUyhLTnWkk7KXzHfyeWAnlrDe1fN77bXl6ia8KT3wPlmA7t9/VPRpnf4Ex9sg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, "node_modules/@types/hast": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", @@ -3767,25 +3008,6 @@ "@types/unist": "*" } }, - "node_modules/@types/http-errors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", - "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@types/http-proxy": { - "version": "1.17.17", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.17.tgz", - "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/jquery": { "version": "3.5.16", "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz", @@ -3799,7 +3021,7 @@ "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@types/mdast": { @@ -3811,14 +3033,6 @@ "@types/unist": "*" } }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/@types/ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", @@ -3829,7 +3043,7 @@ "version": "26.4.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-26.4.0.tgz", "integrity": "sha512-faiGnoIrLH/V8cibOMEAZ8pMw6oXqSukl29ra4mN8GdaB2ZewzeaLj+INpV5N+Z1eKWzY+IzaIZH2EIR6YZRNQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "undici-types": "~8.3.0" @@ -3841,22 +3055,6 @@ "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", "license": "MIT" }, - "node_modules/@types/qs": { - "version": "6.15.1", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", - "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/@types/react": { "version": "18.3.31", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz", @@ -3867,84 +3065,18 @@ "csstype": "^3.2.2" } }, - "node_modules/@types/retry": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", - "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/@types/semver": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.8.0.tgz", "integrity": "sha512-1mAINjtQCXXeLkJ9ehXkwOcBpqtLxiVtKhpUf83DdRNdQKV0iXZpaHYqRr7nj+wvxuJzoAmAwXI+sCNMv1CzLQ==", "license": "MIT" }, - "node_modules/@types/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", - "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/serve-index": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", - "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/express": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", - "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "<1" - } - }, - "node_modules/@types/serve-static/node_modules/@types/send": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", - "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, "node_modules/@types/sizzle": { "version": "2.3.10", "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.10.tgz", "integrity": "sha512-TC0dmN0K8YcWEAEfiPi5gJP14eJe30TTGjkvek3iM/1NdHHsdCA/Td6GvNndMOo/iSnIsZ4HuuhrYPDAmbxzww==", "license": "MIT" }, - "node_modules/@types/sockjs": { - "version": "0.3.36", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", - "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", @@ -3964,17 +3096,6 @@ "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", "license": "MIT" }, - "node_modules/@types/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.68.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.68.0.tgz", @@ -4761,7 +3882,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", @@ -4772,28 +3893,28 @@ "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==", - "devOptional": true, + "dev": true, "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==", - "devOptional": true, + "dev": true, "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==", - "devOptional": true, + "dev": true, "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==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", @@ -4805,14 +3926,14 @@ "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==", - "devOptional": true, + "dev": true, "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==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -4825,7 +3946,7 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" @@ -4835,7 +3956,7 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" @@ -4845,14 +3966,14 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "devOptional": true, + "dev": true, "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==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -4869,7 +3990,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -4883,7 +4004,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -4896,7 +4017,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -4911,7 +4032,7 @@ "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==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -4969,14 +4090,14 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "devOptional": true, + "dev": true, "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==", - "devOptional": true, + "dev": true, "license": "Apache-2.0" }, "node_modules/@yr/monotone-cubic-spline": { @@ -5009,32 +4130,6 @@ "node": ">=6.5" } }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/accepts/node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/acorn": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", @@ -5051,7 +4146,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "devOptional": true, + "dev": true, "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -5123,7 +4218,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" @@ -5132,20 +4227,6 @@ "ajv": "^8.8.2" } }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "license": "Apache-2.0", - "peer": true, - "bin": { - "ansi-html": "bin/ansi-html" - } - }, "node_modules/ansi-regex": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", @@ -5175,35 +4256,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/anynum": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/anynum/-/anynum-1.0.1.tgz", @@ -5247,14 +4299,6 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/asn1.js": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", @@ -5274,22 +4318,6 @@ "dev": true, "license": "MIT" }, - "node_modules/asn1js": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.10.tgz", - "integrity": "sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "pvtsutils": "^1.3.6", - "pvutils": "^1.1.5", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/assert": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", @@ -5417,45 +4445,18 @@ "node": ">=4" } }, - "node_modules/axios": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz", - "integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.16.0", - "form-data": "^4.0.6", - "https-proxy-agent": "^5.0.1", - "proxy-from-env": "^2.1.0" - } - }, - "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==", - "dev": true, - "license": "MIT", - "peer": true, - "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/axios": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz", + "integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.6", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, "node_modules/bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", @@ -5470,7 +4471,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": "18 || 20 || >=22" @@ -5507,7 +4508,7 @@ "version": "2.11.20", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.20.tgz", "integrity": "sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -5516,28 +4517,6 @@ "node": ">=6.0.0" } }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/bindings": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", @@ -5626,118 +4605,18 @@ "dev": true, "license": "MIT" }, - "node_modules/body-parser": { - "version": "1.20.6", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.6.tgz", - "integrity": "sha512-p5tAzS57i5MV9fZFDj9LeIiTZEufbSe2eDozP+ElheSUq1m74CRq1jI4mYNDdVs9vQztXFLuk/Gd6BWTdwRJ5g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "bytes": "~3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "~1.2.0", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "on-finished": "~2.4.1", - "qs": "~6.15.1", - "raw-body": "~2.5.3", - "type-is": "~1.6.18", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.15.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", - "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "es-define-property": "^1.0.1", - "side-channel": "^1.1.1" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/bonjour-service": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.4.4.tgz", - "integrity": "sha512-jCZcVv7eoc4QesRscwEZtSROBen+6LpKAmBIsQYQrsAeVHLyMXWX/t6eIV5KiRZYNUBl8eVqImEEMQ8L5+c/Kw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "multicast-dns": "^7.2.5" - } - }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/brace-expansion": { "version": "5.0.9", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -5903,7 +4782,7 @@ "version": "4.28.8", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz", "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==", - "devOptional": true, + "dev": true, "funding": [ { "type": "opencollective", @@ -5962,7 +4841,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/buffer-xor": { @@ -5979,51 +4858,12 @@ "dev": true, "license": "MIT" }, - "node_modules/bundle-name": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", - "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "run-applescript": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/byte-length": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/byte-length/-/byte-length-1.0.2.tgz", "integrity": "sha512-ovBpjmsgd/teRmgcPh23d4gJvxDoXtAzEL9xTfMU8Yc2kqCDb7L9jAG0XHl1nzuGl+h3ebCIF1i62UFyA9V/2Q==", "license": "MIT" }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/bytestreamjs": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/bytestreamjs/-/bytestreamjs-2.0.1.tgz", - "integrity": "sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/cacache": { "version": "19.0.1", "resolved": "https://registry.npmjs.org/cacache/-/cacache-19.0.1.tgz", @@ -6150,7 +4990,7 @@ "version": "1.0.30001810", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", - "devOptional": true, + "dev": true, "funding": [ { "type": "opencollective", @@ -6283,7 +5123,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6.0" @@ -6432,87 +5272,12 @@ "node": ">= 12.0.0" } }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/compression": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", - "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "bytes": "3.1.2", - "compressible": "~2.0.18", - "debug": "2.6.9", - "negotiator": "~0.6.4", - "on-headers": "~1.1.0", - "safe-buffer": "5.2.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/compression/node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/confbox": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", "license": "MIT" }, - "node_modules/connect-history-api-fallback": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", - "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.8" - } - }, "node_modules/console-browserify": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", @@ -6526,20 +5291,6 @@ "dev": true, "license": "MIT" }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/content-type": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", @@ -6562,25 +5313,6 @@ "dev": true, "license": "MIT" }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", - "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/copy-anything": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.1.0.tgz", @@ -6698,7 +5430,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -6822,7 +5554,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "devOptional": true, + "dev": true, "license": "MIT", "bin": { "cssesc": "bin/cssesc" @@ -7035,40 +5767,8 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/default-browser": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz", - "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "bundle-name": "^4.1.0", - "default-browser-id": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser-id": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", - "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT" }, "node_modules/define-data-property": { "version": "1.1.4", @@ -7088,20 +5788,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/define-lazy-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/define-properties": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", @@ -7129,17 +5815,6 @@ "node": ">=0.4.0" } }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -7160,18 +5835,6 @@ "minimalistic-assert": "^1.0.0" } }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, "node_modules/detect-indent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-7.0.2.tgz", @@ -7208,14 +5871,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/devlop": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", @@ -7262,20 +5917,6 @@ "license": "MIT", "optional": true }, - "node_modules/dns-packet": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", - "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@leichtgewicht/ip-codec": "^2.0.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", @@ -7392,19 +6033,11 @@ "license": "MIT", "optional": true }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/electron-to-chromium": { "version": "1.5.416", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.416.tgz", "integrity": "sha512-K6bvB2BjnNrugtIih6ewlbBI9DXa976jIdiIlRLHhBoEI9a4JaQjjHyF+A1IQI543aQYR4LnmOrT/K5fZj0aPA==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/elliptic": { @@ -7448,19 +6081,8 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } + "license": "MIT", + "optional": true }, "node_modules/encoding": { "version": "0.1.13", @@ -7488,7 +6110,7 @@ "version": "5.24.5", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz", "integrity": "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -7573,7 +6195,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/es-object-atoms": { @@ -7607,7 +6229,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -7623,7 +6245,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -7636,7 +6258,7 @@ "version": "10.9.1", "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.9.1.tgz", "integrity": "sha512-9VaAkDURekixUQJy0oJYl2DcN6oKMfxay7XzaGYAWQwsb6qfKf+x76R2k1L8kb1boc+FyCAaTA9GmiKaaiaF+A==", - "devOptional": true, + "dev": true, "license": "MIT", "workspaces": [ "packages/*" @@ -7841,7 +6463,7 @@ "version": "10.10.0", "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.10.0.tgz", "integrity": "sha512-dL9x9rBHqqNcByWiLOHK6L0SB97V82/NC0cZRn9cXPjM7pCuWlpQQP9bFH4vjBv80ej1ZpzAkuD8zWH1o9bZbA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", @@ -7873,7 +6495,7 @@ "version": "7.8.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "devOptional": true, + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -7886,7 +6508,7 @@ "version": "9.1.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", - "devOptional": true, + "dev": true, "license": "BSD-2-Clause", "dependencies": { "@types/esrecurse": "^4.3.1", @@ -7905,7 +6527,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7918,7 +6540,7 @@ "version": "6.15.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -7935,7 +6557,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" @@ -7948,7 +6570,7 @@ "version": "11.2.0", "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", - "devOptional": true, + "dev": true, "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.16.0", @@ -7966,14 +6588,14 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/espree": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "devOptional": true, + "dev": true, "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.15.0", @@ -7991,7 +6613,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "devOptional": true, + "dev": true, "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" @@ -8004,7 +6626,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "devOptional": true, + "dev": true, "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -8017,7 +6639,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "devOptional": true, + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -8043,23 +6665,12 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "devOptional": true, + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/event-target-shim": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", @@ -8080,7 +6691,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=0.8.x" @@ -8126,102 +6737,6 @@ "license": "Apache-2.0", "optional": true }, - "node_modules/express": { - "version": "4.22.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", - "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "~1.20.5", - "content-disposition": "~0.5.4", - "content-type": "~1.0.4", - "cookie": "~0.7.1", - "cookie-signature": "~1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.3.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "~0.1.12", - "proxy-addr": "~2.0.7", - "qs": "~6.15.1", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "~0.19.0", - "serve-static": "~1.16.2", - "setprototypeof": "1.2.0", - "statuses": "~2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express/node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/express/node_modules/qs": { - "version": "6.15.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", - "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "es-define-property": "^1.0.1", - "side-channel": "^1.1.1" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/exsolve": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.1.1.tgz", @@ -8274,14 +6789,14 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/fast-uri": { @@ -8359,20 +6874,6 @@ "reusify": "^1.0.4" } }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -8417,7 +6918,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "flat-cache": "^4.0.0" @@ -8447,50 +6948,11 @@ "node": ">=8" } }, - "node_modules/finalhandler": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", - "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "statuses": "~2.0.2", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "locate-path": "^6.0.0", @@ -8517,7 +6979,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", @@ -8531,7 +6993,7 @@ "version": "3.4.4", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/floating-vue": { @@ -8653,28 +7115,6 @@ "node": ">=12.20.0" } }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -8836,7 +7276,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -8845,24 +7285,6 @@ "node": ">=10.13.0" } }, - "node_modules/glob-to-regex.js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/glob-to-regex.js/-/glob-to-regex.js-1.2.0.tgz", - "integrity": "sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, "node_modules/glob/node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -9008,7 +7430,7 @@ "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==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/gridstack": { @@ -9027,19 +7449,11 @@ ], "license": "MIT" }, - "node_modules/handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true, - "license": "MIT", - "peer": true - }, "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==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9274,64 +7688,6 @@ "integrity": "sha512-ECg1JFG0YzehicQaogenlcs2qg6WsXQsxtnbr1i696u5tLUjtJdQAh0u2g0Q5YV45f263Ta1GnUJsc8WIfJf4Q==", "license": "MIT" }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "node_modules/hpack.js/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/hpack.js/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==", - "dev": true, - "license": "MIT", - "peer": true, - "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/hpack.js/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==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/hpack.js/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==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/html-entities": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", @@ -9410,60 +7766,6 @@ "license": "BSD-2-Clause", "optional": true }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", - "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -9486,57 +7788,9 @@ "dev": true, "license": "MIT", "optional": true, - "engines": { - "node": ">= 14" - } - }, - "node_modules/http-proxy-middleware": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.10.tgz", - "integrity": "sha512-RKzRWNPxUZqbuk3BC5mGVJbBnWgr+diEnjJexIOytFbBzDy88Fbh/YvBr3DsNrl1jYAfjWfpATEv0NO35FDuPQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" - }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } - } - }, - "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/http-proxy/node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true, - "license": "MIT", - "peer": true + "engines": { + "node": ">= 14" + } }, "node_modules/https-browserify": { "version": "1.0.0", @@ -9558,17 +7812,6 @@ "node": ">= 6" } }, - "node_modules/hyperdyperid": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", - "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10.18" - } - }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -9621,7 +7864,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -9685,7 +7928,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -9732,17 +7975,6 @@ "node": ">= 12" } }, - "node_modules/ipaddr.js": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.5.0.tgz", - "integrity": "sha512-aq+t5NAc+cS6rZQQVWC2x98CPqGtKKTMDd4Gaodv0wShnItdKg/51djkGJ1hqH+Oy0ivDftCbSLCQob8zso01w==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 10" - } - }, "node_modules/is-absolute-url": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", @@ -9803,20 +8035,6 @@ "dev": true, "license": "MIT" }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -9862,23 +8080,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -9942,26 +8143,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "is-docker": "^3.0.0" - }, - "bin": { - "is-inside-container": "cli.js" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-nan": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", @@ -9979,20 +8160,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-network-error": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.2.tgz", - "integrity": "sha512-PhBY86zaxNZUuWP6h13Vu5oFe0XY6/UlKzQnYFELzGVHygP3MxmvTfYSG7GN3aIab/iWudSMgjSnG9Dq+nHrgA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -10100,23 +8267,6 @@ ], "license": "MIT" }, - "node_modules/is-wsl": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", - "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "is-inside-container": "^1.0.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -10128,7 +8278,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/isobject": { @@ -10201,7 +8351,7 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -10216,7 +8366,7 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -10285,7 +8435,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/json-parse-even-better-errors": { @@ -10305,7 +8455,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/json5": { @@ -10325,7 +8475,7 @@ "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "json-buffer": "3.0.1" @@ -10348,18 +8498,6 @@ "dev": true, "license": "MIT" }, - "node_modules/launch-editor": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.14.1.tgz", - "integrity": "sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "picocolors": "^1.1.1", - "shell-quote": "^1.8.4" - } - }, "node_modules/layerr": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/layerr/-/layerr-3.0.0.tgz", @@ -10385,7 +8523,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", @@ -10417,7 +8555,7 @@ "version": "1.33.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", - "devOptional": true, + "dev": true, "license": "MPL-2.0", "dependencies": { "detect-libc": "^2.0.3" @@ -10708,7 +8846,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "p-locate": "^5.0.0" @@ -11134,45 +9272,6 @@ "dev": true, "license": "CC0-1.0" }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memfs": { - "version": "4.68.2", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.68.2.tgz", - "integrity": "sha512-Un1ElEBoIdPI9kg0sm3LebVEuEViodfIvlaG8Z1MFXa7ZnR9vWuPKUo3dt/vuWY2ivc05l76B5QOjdgCzAzmGw==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@jsonjoy.com/fs-core": "4.68.2", - "@jsonjoy.com/fs-fsa": "4.68.2", - "@jsonjoy.com/fs-node": "4.68.2", - "@jsonjoy.com/fs-node-builtins": "4.68.2", - "@jsonjoy.com/fs-node-to-fsa": "4.68.2", - "@jsonjoy.com/fs-node-utils": "4.68.2", - "@jsonjoy.com/fs-print": "4.68.2", - "@jsonjoy.com/fs-snapshot": "4.68.2", - "@jsonjoy.com/json-pack": "^1.11.0", - "@jsonjoy.com/util": "^1.9.0", - "glob-to-regex.js": "^1.0.1", - "thingies": "^2.5.0", - "tree-dump": "^1.0.3", - "tslib": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - } - }, "node_modules/meow": { "version": "14.1.0", "resolved": "https://registry.npmjs.org/meow/-/meow-14.1.0.tgz", @@ -11186,22 +9285,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "dev": true, - "license": "MIT", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/merge2": { @@ -11214,17 +9302,6 @@ "node": ">= 8" } }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/micromark": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", @@ -11715,20 +9792,6 @@ "dev": true, "license": "MIT" }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -11782,7 +9845,7 @@ "version": "10.2.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", - "devOptional": true, + "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "brace-expansion": "^5.0.8" @@ -11809,7 +9872,7 @@ "version": "5.8.0", "resolved": "https://registry.npmjs.org/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.8.0.tgz", "integrity": "sha512-2cT9+goJfBhtMz+gJqejSf09ClgmYhPhccRb/fb0ztVbixt0BkO8mRuI26FoPPuUNkRk6iEDryWAIouc5W8eJA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.31", @@ -12095,21 +10158,6 @@ "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", "license": "MIT" }, - "node_modules/multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" - }, - "bin": { - "multicast-dns": "cli.js" - } - }, "node_modules/nan": { "version": "2.22.2", "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.2.tgz", @@ -12148,7 +10196,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/natural-orderby": { @@ -12407,7 +10455,7 @@ "version": "2.0.54", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz", "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -12478,7 +10526,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "devOptional": true, + "dev": true, "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" @@ -12555,14 +10603,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/obug": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", @@ -12577,31 +10617,6 @@ "node": ">=12.20.0" } }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/on-headers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", - "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -12613,31 +10628,11 @@ "wrappy": "1" } }, - "node_modules/open": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", - "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "default-browser": "^5.2.1", - "define-lazy-prop": "^3.0.0", - "is-inside-container": "^1.0.0", - "wsl-utils": "^0.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "deep-is": "^0.1.3", @@ -12668,7 +10663,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -12684,7 +10679,7 @@ "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==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "p-limit": "^3.0.2" @@ -12726,36 +10721,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-retry": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", - "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/retry": "0.12.2", - "is-network-error": "^1.0.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-retry/node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 4" - } - }, "node_modules/p-timeout": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.1.tgz", @@ -12891,17 +10856,6 @@ "dev": true, "license": "MIT" }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", @@ -12913,7 +10867,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -12938,7 +10892,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -12983,14 +10937,6 @@ "license": "ISC", "optional": true }, - "node_modules/path-to-regexp": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", - "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/pathe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", @@ -13140,25 +11086,6 @@ "pathe": "^2.0.3" } }, - "node_modules/pkijs": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.4.0.tgz", - "integrity": "sha512-emEcLuomt2j03vxD54giVB4SxTjnsqkU692xZOZXHDVoYyypEm+b3jpiTcc+Cf+myooc+/Ly0z01jqeNHVgJGw==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "@noble/hashes": "1.4.0", - "asn1js": "^3.0.6", - "bytestreamjs": "^2.0.1", - "pvtsutils": "^1.3.6", - "pvutils": "^1.1.3", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, "node_modules/playwright": { "version": "1.62.1", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.62.1.tgz", @@ -13377,7 +11304,7 @@ "version": "7.1.5", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.5.tgz", "integrity": "sha512-KvvtD7SrlBP7dlgkBghEE3r84CABm5SmV2aNcG4oCA+qDnJ/tvKonFVvwWAyyWUEwxuNawdfEAZKP9zM3oZ2Uw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -13427,7 +11354,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8.0" @@ -13624,44 +11551,18 @@ "integrity": "sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==", "license": "MIT", "dependencies": { - "prosemirror-model": "^1.21.0" - } - }, - "node_modules/prosemirror-view": { - "version": "1.42.3", - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.42.3.tgz", - "integrity": "sha512-oTN7EtH+CpwxU9NrwEYWd0UZ4JUx7l048l5A2Xppm4p/60isZYLnth9QVQmC3VRIvdrIWCxwZSd+Uz791G31/w==", - "license": "MIT", - "dependencies": { - "prosemirror-model": "^1.25.8", - "prosemirror-state": "^1.0.0", - "prosemirror-transform": "^1.1.0" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" + "prosemirror-model": "^1.21.0" } }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, + "node_modules/prosemirror-view": { + "version": "1.42.3", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.42.3.tgz", + "integrity": "sha512-oTN7EtH+CpwxU9NrwEYWd0UZ4JUx7l048l5A2Xppm4p/60isZYLnth9QVQmC3VRIvdrIWCxwZSd+Uz791G31/w==", "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.10" + "dependencies": { + "prosemirror-model": "^1.25.8", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0" } }, "node_modules/proxy-from-env": { @@ -13711,32 +11612,10 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/pvtsutils": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", - "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "tslib": "^2.8.1" - } - }, - "node_modules/pvutils": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.2.0.tgz", - "integrity": "sha512-BbubeCEyTuQjVMakvJQ/Sxbc93F2pwmbsxONT/ZRrwU7Ua38d8unYTwXpTVLAKJ4BDuH9IGztCjQcd/N/39Dvg==", "dev": true, "license": "MIT", - "peer": true, "engines": { - "node": ">=16.0.0" + "node": ">=6" } }, "node_modules/qified": { @@ -13872,48 +11751,6 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", - "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -13974,14 +11811,6 @@ "node": ">= 10.13.0" } }, - "node_modules/reflect-metadata": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", - "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", - "dev": true, - "license": "Apache-2.0", - "peer": true - }, "node_modules/rehype-external-links": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/rehype-external-links/-/rehype-external-links-3.0.0.tgz", @@ -14294,7 +12123,7 @@ "version": "1.2.6", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.6.tgz", "integrity": "sha512-vMM4q3aixf46GiF1Kok8jDPFsEpXgFWGjUHXNkNHNm+Y2adXAG2dbX91jkti3i0ZRsOlcmbuzAz1poObSHCmUA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@oxc-project/types": "=0.147.0", @@ -14330,20 +12159,6 @@ "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==", "license": "MIT" }, - "node_modules/run-applescript": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", - "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -14412,7 +12227,8 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/sass": { "version": "1.103.1", @@ -14487,7 +12303,7 @@ "version": "4.3.3", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", @@ -14507,7 +12323,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -14538,29 +12354,6 @@ "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", "license": "MIT" }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/selfsigned": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-5.5.0.tgz", - "integrity": "sha512-ftnu3TW4+3eBfLRFnDEkzGxSF/10BJBkaLJuBHZX0kiPS7bRdlpZGu6YGt4KngMkdTwJE6MbjavFpqHvqVt+Ew==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@peculiar/x509": "^1.14.2", - "pkijs": "^3.3.3" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -14571,151 +12364,6 @@ "semver": "bin/semver.js" } }, - "node_modules/send": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", - "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.4.1", - "range-parser": "~1.2.1", - "statuses": "~2.0.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/serve-index": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.2.tgz", - "integrity": "sha512-KDj11HScOaLmrPxl70KYNW1PksP4Nb/CLL2yvC+Qd2kHMPEEpfc4Re2e4FOay+bC/+XQl/7zAcWON3JVo5v3KQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "accepts": "~1.3.8", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.8.0", - "mime-types": "~2.1.35", - "parseurl": "~1.3.3" - }, - "engines": { - "node": ">= 0.8.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/serve-index/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/serve-index/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/serve-index/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-static": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", - "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "~0.19.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -14741,14 +12389,6 @@ "dev": true, "license": "MIT" }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, - "license": "ISC", - "peer": true - }, "node_modules/sha.js": { "version": "2.4.12", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", @@ -14787,7 +12427,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -14800,24 +12440,10 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/shell-quote": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.10.0.tgz", - "integrity": "sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==", "dev": true, "license": "MIT", - "peer": true, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, "node_modules/side-channel": { @@ -15022,19 +12648,6 @@ "node": ">=0.10" } }, - "node_modules/sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" - } - }, "node_modules/socks": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", @@ -15130,7 +12743,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "devOptional": true, + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -15149,7 +12762,7 @@ "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==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -15213,56 +12826,6 @@ "dev": true, "license": "CC0-1.0" }, - "node_modules/spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, - "node_modules/spdy-transport/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==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/speakingurl": { "version": "14.0.1", "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", @@ -15305,17 +12868,6 @@ "dev": true, "license": "MIT" }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/std-env": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", @@ -16034,7 +13586,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -16133,7 +13685,7 @@ "version": "5.51.2", "resolved": "https://registry.npmjs.org/terser/-/terser-5.51.2.tgz", "integrity": "sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==", - "devOptional": true, + "dev": true, "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -16213,34 +13765,8 @@ "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==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/thingies": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.6.1.tgz", - "integrity": "sha512-cV/CMGTK3M4MlnJ/0At6ismOw/A0EEniDNScajjz/Br3c1sqE72YD01rGpPTKwd27wAxI5Pr+6+0w8yofzFRYw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "^2" - } - }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/timers-browserify": { "version": "2.0.12", @@ -16343,35 +13869,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tree-dump": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz", - "integrity": "sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, "node_modules/tributejs": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/tributejs/-/tributejs-5.1.3.tgz", @@ -16411,43 +13908,6 @@ "typescript": ">=4.8.4" } }, - "node_modules/ts-loader": { - "version": "9.6.2", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.6.2.tgz", - "integrity": "sha512-R4iuczmtgxvtuI556s+hTZ6/7Ee03VCAk/l/M8LY1OAsUgB7YydsCxkgq9D9pKRaD7GJqUi2u8fp9zZP/ufjKA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "chalk": "^4.1.0", - "picomatch": "^4.0.0", - "source-map": "^0.7.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "loader-utils": "*", - "typescript": "*", - "webpack": "^4.0.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "loader-utils": { - "optional": true - } - } - }, - "node_modules/ts-loader/node_modules/source-map": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "engines": { - "node": ">= 12" - } - }, "node_modules/ts-md5": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ts-md5/-/ts-md5-2.0.1.tgz", @@ -16457,36 +13917,6 @@ "node": ">=18" } }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD", - "peer": true - }, - "node_modules/tsyringe": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz", - "integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "tslib": "^1.9.3" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/tsyringe/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, - "license": "0BSD", - "peer": true - }, "node_modules/tty-browserify": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", @@ -16512,7 +13942,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" @@ -16534,21 +13964,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/typed-array-buffer": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", @@ -16568,7 +13983,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -16618,7 +14033,7 @@ "version": "8.3.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/unicorn-magic": { @@ -16776,17 +14191,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/unplugin": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.3.0.tgz", @@ -16861,7 +14265,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz", "integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==", - "devOptional": true, + "dev": true, "funding": [ { "type": "opencollective", @@ -16892,7 +14296,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "devOptional": true, + "dev": true, "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" @@ -16956,31 +14360,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "uuid": "dist/bin/uuid" - } + "license": "MIT" }, "node_modules/validate-npm-package-license": { "version": "3.0.4", @@ -17004,17 +14385,6 @@ "spdx-license-ids": "^3.0.0" } }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", @@ -17047,7 +14417,7 @@ "version": "8.2.2", "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz", "integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.33.0", @@ -17305,7 +14675,7 @@ "version": "10.4.1", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.4.1.tgz", "integrity": "sha512-Gk6gRDj0n/fkRa3C3l0bBheoBckUq/Rs0F/TvMWIS6nzzx67amAViMe9CkNgsP2tXyQONvGiHQESHwFtZ3aYDA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -17329,7 +14699,7 @@ "version": "7.8.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "devOptional": true, + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -17429,7 +14799,7 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.2.tgz", "integrity": "sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.1.2" @@ -17438,17 +14808,6 @@ "node": ">=10.13.0" } }, - "node_modules/wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "minimalistic-assert": "^1.0.0" - } - }, "node_modules/web-streams-polyfill": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", @@ -17529,7 +14888,7 @@ "version": "5.110.2", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.110.2.tgz", "integrity": "sha512-TciLrfM7zgEjqGdY851HkirDsSPQgTFsWQpl9oHqMAMYsHhEC0bKjscvjpnz+pzx10hLC8qISApGrsnrCP4UtQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.8", @@ -17621,193 +14980,6 @@ "node": ">=18" } }, - "node_modules/webpack-dev-middleware": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.5.tgz", - "integrity": "sha512-uxQ6YqGdE4hgDKNf7hUiPXOdtkXvBJXrfEGYSx7P7LC8hnUYGK70X6xQXUvXeNyBDDcsiQXpG2m3G9vxowaEuA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "colorette": "^2.0.10", - "memfs": "^4.43.1", - "mime-types": "^3.0.1", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - } - } - }, - "node_modules/webpack-dev-middleware/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==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/webpack-dev-middleware/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/webpack-dev-server": { - "version": "5.2.6", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.6.tgz", - "integrity": "sha512-HNLRmamRvVavZQ+avceZifmv8hmdUjg43t6MI4SqJDwFdW7RPQwH5vzGhDRZSX59SgfbeHhLnq3g+uooWo7pVw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/bonjour": "^3.5.13", - "@types/connect-history-api-fallback": "^1.5.4", - "@types/express": "^4.17.25", - "@types/express-serve-static-core": "^4.17.21", - "@types/serve-index": "^1.9.4", - "@types/serve-static": "^1.15.5", - "@types/sockjs": "^0.3.36", - "@types/ws": "^8.5.10", - "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.2.1", - "chokidar": "^3.6.0", - "colorette": "^2.0.10", - "compression": "^1.8.1", - "connect-history-api-fallback": "^2.0.0", - "express": "^4.22.1", - "graceful-fs": "^4.2.6", - "http-proxy-middleware": "^2.0.9", - "ipaddr.js": "^2.1.0", - "launch-editor": "^2.14.1", - "open": "^10.0.3", - "p-retry": "^6.2.0", - "schema-utils": "^4.2.0", - "selfsigned": "^5.5.0", - "serve-index": "^1.9.1", - "sockjs": "^0.3.24", - "spdy": "^4.0.2", - "webpack-dev-middleware": "^7.4.2", - "ws": "^8.18.0" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - }, - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-dev-server/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/webpack-dev-server/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/webpack-dev-server/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/webpack-dev-server/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/webpack-merge": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", @@ -17827,7 +14999,7 @@ "version": "3.5.1", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.1.tgz", "integrity": "sha512-jyuiGJdtvY434z5bUZrjz67v76/ePNvFZTp9Mdz29IlH4+GPsgyGjiv0fKI+M7BdkU6ADjulUcKAd3tUK3WlEw==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=10.13.0" @@ -17843,44 +15015,17 @@ "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" } }, - "node_modules/websocket-driver": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.5.tgz", - "integrity": "sha512-ZL2+3c7kMBdIRCMz6l8jQMHyGVxj+UL+xVk74Ombiciboca8rHa15L86B19E5oh1pL9Ii/uj54gtsIrZGMo6zA==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -17942,7 +15087,7 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -18071,51 +15216,11 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/ws": { - "version": "8.21.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", - "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/wsl-utils": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", - "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "is-wsl": "^3.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/xml-name-validator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18" @@ -18173,7 +15278,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=10" From 67e0f6c12a1641fabafe6387068d0b5f3482f12d Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Mon, 31 Aug 2026 09:46:56 +0200 Subject: [PATCH 17/21] chore(deps): take @conduction/nextcloud-vue 2.27.0 (#1050) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Brings this app level with the rest of the fleet, which went straight to 2.27.0 — this one was bumped to 2.26.0 minutes before 2.27.0 published. Three lines: the extraneous entries were already pruned by the 2.26.0 bump, so this is the version change and nothing else. Co-authored-by: Conduction Release Bot --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 35fb4255b..7cefc5257 100644 --- a/package-lock.json +++ b/package-lock.json @@ -562,9 +562,9 @@ } }, "node_modules/@conduction/nextcloud-vue": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-2.26.0.tgz", - "integrity": "sha512-PrEd1Ej9UMXTw7qzq6WqqPnwdO2yLlJvj8/Lz7fGbtrUbO8xUAkPwgJlKNbsWHv2DhhF5G/MRN4ZA+YvNDaJIg==", + "version": "2.27.0", + "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-2.27.0.tgz", + "integrity": "sha512-64IS6VrAp4c+Hr9AAS9/z6AzznmaPfbO4GrZtmOX57dLCpJORkn5M/wSKpAC6ZG+gUHTJeXDUiabut9bV0kRnQ==", "license": "EUPL-1.2", "dependencies": { "@ckpack/vue-color": "^1.6.0", From aec6caae27c788abd7cc86a3bd780706b8631363 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Mon, 31 Aug 2026 10:35:14 +0200 Subject: [PATCH 18/21] fix(e2e): seed the five Goals goals-pages.spec.ts asserts on (#1052) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(e2e): seed the five Goals goals-pages.spec.ts asserts on `Goals: index lists all five seeded goals` failed on getByText('Duurzame omzetgroei 2028') -> element(s) not found. The five goals it names were never created on CI. The spec's docblock points at lib/Settings/register.d/66-organisation-goals.json, but that file declares only the Goal SCHEMA. The five objects live in three different profile files -- association.json (1), corporate.json (2), municipality.json (2) -- so no single `example_profile` yields all five, and the seed deliberately picks `none` to keep a whole demo dataset out of the lists other specs assert on. The spec was written against the older behaviour where installing planted everything. Measured on development 67e0f6c1: E2E 4 failed / 139 passed, this among them. Seeded in the governance fixture, beside the objects the other specs need: - No SEED_TAG prefix. The titles ARE the assertion and are matched with { exact: true }, so prefixing them the way the sibling objects are prefixed would break the test this exists to fix. - Titles, descriptions, horizons, deadlines and statuses copied verbatim from the profiles, so the fixture and the shipped example sets cannot drift into disagreeing about what a Goal looks like. - `body` repointed at this run's governance body. The profiles reference their own bodies by slug (gemeenteraad-amsterdam, ledenraad-vng, raad-van-bestuur-acme-bv), none of which exist here; a dangling reference would seed an object the index cannot resolve. `owner` is dropped for the same reason -- femke-halsema is not a user on this instance, and the field is not required. - 'goal': 5 added to the readability verifier, for the reason that block exists: a create that answered 2xx but is not listable would leave the spec failing on "element(s) not found", which reads as a missing feature rather than a seed that did not land. This fixes ONE of decidiq's four E2E failures. The other three are not seeding gaps and are left alone deliberately -- see the PR body. * fix(e2e): seed one built-in ProcessTemplate so the list is not empty `Template list shows built-in templates as read-only` failed at expect(page.locator('[data-testid="process-template-list"]')).toBeVisible() Received: hidden not because the list is missing but because it is EMPTY. ProcessTemplates.vue renders `
    ` regardless of row count, and an empty
      is a zero-height box, which Playwright reports as hidden. ProcessTemplateService::list() already carries a comment describing exactly this shape from the last time it returned zero rows. Same root cause as the Goals in the previous commit: the built-in templates are not shipped with the schema, they live in the profile files (association.json, corporate.json and municipality.json declare three each), so `example_profile=none` leaves the catalogue empty. ONE is seeded, deliberately. The spec asserts the list renders, then takes the FIRST item carrying `process-template-builtin` and checks it is read-only. Seeding all nine would push a full catalogue into every other list that reads this schema, which is what the `none` profile exists to avoid. `Municipal Council` is the template that matches the rest of this fixture — the governance body seeded above is a Gemeenteraad. It is copied verbatim from municipality.json (states, transitions, guards, voting rule and quorum rule included), verified structurally identical minus `@self` and `slug`: `@self` is import metadata the object API sets itself, and the slug is assigned server-side. 'process-template': 1 added to the readability verifier for the same reason as 'goal': 5 — an unlistable create would resurface as "hidden", which reads as a CSS or mount problem rather than a seed that did not land. --------- Co-authored-by: Conduction Release Bot --- tests/e2e/ci-seed.sh | 109 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/tests/e2e/ci-seed.sh b/tests/e2e/ci-seed.sh index 249bccece..b53dfa93a 100755 --- a/tests/e2e/ci-seed.sh +++ b/tests/e2e/ci-seed.sh @@ -619,6 +619,104 @@ else # lib/Migration/MigrateActionItemsToDeckLeaf.php is an explicit no-op.) # Action items are seeded per-spec through decidiq's own endpoint, # POST /apps/decidiq/api/action-items → ActionItemWriter → TaskService. + # ── The five Goals `goals-pages.spec.ts` asserts on ──────────────────────── + # + # 🔴 THESE TITLES ARE THE ASSERTION, SO THEY CARRY NO ${SEED_TAG} PREFIX. + # `SEEDED_GOAL_TITLES` matches with `{ exact: true }`; prefixing them the way + # the objects above are prefixed would break the very test this seeds for. + # + # WHY THEY HAVE TO BE SEEDED HERE AT ALL. The spec's docblock points at + # lib/Settings/register.d/66-organisation-goals.json, but that file declares + # only the `Goal` SCHEMA. The five objects live in three different profile + # files — association.json (1), corporate.json (2), municipality.json (2) — + # so NO single `example_profile` produces all five, and CI picks `none` + # (see the setup/config call below) precisely to keep a whole demo dataset + # out of the lists other specs assert on. The spec was written against the + # older behaviour where installing planted everything. + # + # Measured on development 2026-08-31: E2E 4 failed / 139 passed, one of them + # `Goals: index lists all five seeded goals` failing on + # `getByText('Duurzame omzetgroei 2028')` → element(s) not found. + # + # Titles, descriptions, horizons, deadlines and statuses are copied verbatim + # from those profiles so the fixture and the shipped example sets cannot + # drift into disagreeing about what a Goal looks like. + # + # `body` is repointed at THIS run's governance body. The profiles reference + # their own bodies by slug (`gemeenteraad-amsterdam`, `ledenraad-vng`, + # `raad-van-bestuur-acme-bv`), none of which exist here — a dangling + # reference would seed an object the Goals index cannot resolve or render. + # `owner` is dropped for the same reason: `femke-halsema` is not a user on + # this instance, and it is not a required field. + seed_goal() { + # $1 = title, $2 = description, $3 = horizon, $4 = startDate, + # $5 = deadline, $6 = status, $7 = extra JSON fields (may be empty) + local id + id="$(seed_object goal \ + "{\"title\":\"$1\",\"description\":\"$2\",\"horizon\":\"$3\",\"body\":\"${BODY_ID}\",\"startDate\":\"$4\",\"deadline\":\"$5\",\"status\":\"$6\"$7}" \ + "the Goal \"$1\"")" + echo "[ci-seed] goal ${id} $1" + } + + seed_goal 'Duurzame omzetgroei 2028' \ + 'Structurele omzetgroei realiseren binnen de duurzaamheidsdoelstellingen van de organisatie.' \ + 'multi-year' '2026-01-01' '2028-12-31' 'active' \ + ',"targetValue":20,"currentValue":6,"unit":"% omzetgroei"' + + seed_goal 'Operationele effectiviteit 2026' \ + 'Procesdoorlooptijden binnen norm brengen als uitvoering van de groeidoelstelling.' \ + 'annual' '2026-01-01' '2026-12-31' 'active' \ + ',"targetValue":90,"currentValue":78,"unit":"% doorlooptijd binnen norm"' + + seed_goal 'Amsterdam klimaatneutraal' \ + 'Netto CO2-uitstoot van de gemeentelijke organisatie naar nul in 2050.' \ + 'multi-year' '2026-01-01' '2050-01-01' 'active' \ + ',"targetValue":100,"currentValue":42,"unit":"% CO2-reductie behaald"' + + seed_goal 'Herzien parkeerbeleid vastgesteld' \ + 'Vaststellen van het herziene parkeerbeleid binnenstad.' \ + 'quarterly' '2026-04-01' '2026-09-30' 'at-risk' '' + + seed_goal 'Digitale dienstverlening leden' \ + 'Alle leden kunnen digitaal diensten afnemen bij de vereniging.' \ + 'annual' '2026-01-01' '2026-12-31' 'draft' '' + + # ── One built-in ProcessTemplate ─────────────────────────────────────────── + # + # `process-configuration.spec.ts:41` failed at + # `expect(page.locator('[data-testid="process-template-list"]')).toBeVisible()` + # with `Received: hidden` — NOT because the list is missing, but because it is + # EMPTY. ProcessTemplates.vue renders `
        ` regardless + # of how many rows it has, and an empty `
          ` is a zero-height box, which + # Playwright reports as hidden. ProcessTemplateService::list() already carries + # a comment describing exactly this shape from the last time it returned zero + # rows. + # + # The built-in templates are NOT shipped with the schema: like the Goals + # above, they live in the profile files (association.json, corporate.json and + # municipality.json declare three each), so `example_profile=none` leaves the + # catalogue empty. Same root cause, same fix. + # + # ONE is enough and one is deliberate. The spec asserts the list renders, then + # takes the FIRST item carrying `process-template-builtin` and checks it is + # read-only (duplicate offered, delete withheld). Seeding all nine would push + # a full catalogue into every other list that reads this schema, which is the + # thing the `none` profile exists to avoid. + # + # `Municipal Council` is the one that matches the rest of this fixture — the + # governance body seeded above is a Gemeenteraad — and it is copied verbatim + # from municipality.json (states, transitions, guards, voting rule and quorum + # rule included) so the fixture cannot drift from the shipped template. The + # profile's `@self` and `slug` are dropped: `@self` is import metadata the + # object API sets itself, and the slug is assigned server-side. + # + # Single-quoted deliberately — the payload contains double quotes throughout + # and no apostrophes, so this embeds it byte-for-byte with no escaping. + PROCESS_TEMPLATE_ID="$(seed_object process-template \ + '{"name":"Municipal Council","description":"Legislative decision process for a municipal council (gemeenteraad), Gemeentewet.","context":"legislative","builtIn":true,"initialState":"draft","stateMachine":{"states":[{"name":"draft"},{"name":"proposed"},{"name":"deliberating"},{"name":"voting"},{"name":"decided"},{"name":"enacted"},{"name":"archived"}],"transitions":[{"name":"propose","from":"draft","to":"proposed"},{"name":"deliberate","from":"proposed","to":"deliberating"},{"name":"openVoting","from":"deliberating","to":"voting","chairOnly":true,"guards":["quorum_met","all_amendments_resolved"]},{"name":"decide","from":"voting","to":"decided","chairOnly":true},{"name":"enact","from":"decided","to":"enacted"},{"name":"archive","from":"enacted","to":"archived"}]},"votingRule":{"voteThreshold":"simple-majority","abstentionHandling":"exclude","tieBreakRule":"rejected"},"quorumRequired":true,"quorumRule":"More than half of the seats occupied (Gemeentewet art. 20)","allowDecideWithoutVote":false}' \ + 'the built-in Municipal Council process template')" + echo "[ci-seed] process-template ${PROCESS_TEMPLATE_ID} Municipal Council (built-in)" + echo "[ci-seed] governance fixture seeded." fi @@ -637,6 +735,17 @@ required = { 'agenda-item': 3, 'decision': 3, 'minutes': 1, + # goals-pages.spec.ts asserts all FIVE by exact title, so five is the floor. + # Listed here for the reason this whole block exists: a create that answered + # 2xx but is not listable would leave the spec failing on "element(s) not + # found", which reads as a missing feature rather than a seed that did not + # land. + 'goal': 5, + # process-configuration.spec.ts needs the list to be non-EMPTY, since an + # empty
            is a zero-height box that Playwright reports as hidden. One + # built-in template is the floor; see the seeding note above for why it is + # not the full catalogue. + 'process-template': 1, # NOT action-item: CalDAV-backed and read-only through this API (see above). } From 89e65c54ed6ac644997ff6be15482d4ed56c3b43 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Mon, 31 Aug 2026 10:39:01 +0200 Subject: [PATCH 19/21] fix(e2e): match the minutes widget by id, not by a phrase shown twice (#1053) `v2 grid renders the KPI row, list widgets and governance-health chart` failed with: Error: strict mode violation: getByText('Minutes awaiting approval') resolved to 2 elements 1)

            2)

            The phrase is rendered twice on this dashboard: once as the widget's own heading and once as a KPI card title -- src/manifest.json declares the stats-block with "id": "minutes-in-review", "title": "Minutes awaiting approval", and repeats that title inside content.entries. So the assertion failed on a dashboard that is entirely correct, and it fails louder the more complete the row gets, which is the wrong direction for a layout test. CnWidgetWrapper renders its heading as `

            ` with `titleId = cn-widget-wrapper-title-${widgetId}` and `resolvedWidgetId()` returning the supplied widgetId, so `#cn-widget-wrapper-title-minutes-in-review` addresses exactly the stats-block this line is about -- the same id the manifest declares and the same element the CI log named -- and stays correct if another surface shows the same phrase. Every other assertion in this test already locates its widget by a stable attribute rather than by text; this line was the exception. One of decidiq's four E2E failures. Not related to the seeding gap in #1052. Co-authored-by: Conduction Release Bot --- .../spec-coverage/dashboard-layout.spec.ts | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/e2e/spec-coverage/dashboard-layout.spec.ts b/tests/e2e/spec-coverage/dashboard-layout.spec.ts index 3b0334737..34079f1e5 100644 --- a/tests/e2e/spec-coverage/dashboard-layout.spec.ts +++ b/tests/e2e/spec-coverage/dashboard-layout.spec.ts @@ -51,7 +51,27 @@ test('v2 grid renders the KPI row, list widgets and governance-health chart', as await expect(page.locator('[data-testid="recent-decisions"]')).toBeVisible() // Row 5 — minutes-in-review stats-block (English title) + governance-health chart. - await expect(page.getByText('Minutes awaiting approval')).toBeVisible() + // + // 🔴 MATCH THE WIDGET, NOT THE PHRASE. "Minutes awaiting approval" is rendered + // TWICE on this dashboard — once as the widget's own heading + // (`

            `) and once as a KPI card title + // (`

            `) — so a bare `getByText` is a strict-mode + // violation, not a passing assertion: + // + // Error: strict mode violation: getByText('Minutes awaiting approval') + // resolved to 2 elements + // + // It fails on a dashboard that is entirely correct, and it fails LOUDER the + // more complete the row gets, which is the wrong direction for a layout test. + // + // `CnWidgetWrapper` renders its heading as `

            ` with + // `titleId = cn-widget-wrapper-title-${widgetId}` (CnWidgetWrapper.vue), and + // the widget id here is `minutes-in-review` — the same id src/manifest.json + // declares for this row. So the id addresses exactly the stats-block this + // line is about, and stays correct if a second surface shows the same phrase. + await expect( + page.locator('#cn-widget-wrapper-title-minutes-in-review'), + ).toBeVisible() await expect(page.locator('[data-testid="governance-health"]')).toBeVisible() }) From 676eee9d914c080e5eda786ff999a994752e8deb Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Mon, 31 Aug 2026 10:49:56 +0200 Subject: [PATCH 20/21] fix(e2e): give the viewport-loop test a budget larger than its own waits (#1054) `quick-filter dropdown label "All urgent" renders intact at every tested viewport` failed as a bare: Test timeout of 20000ms exceeded. The test could not pass reliably no matter how healthy the app was. playwright.config.ts sets `timeout: 20_000` per test. This one loops THREE viewports, and each iteration navigates and then allows `waitForSelector(15_000)` plus `expect(select).toBeVisible({ 10_000 })` -- 25s of permitted waiting in the FIRST iteration alone, against a 20s total budget. The symptom is misleading in a specific way: a whole-test timeout names no element, so it reads like a slow or broken dropdown rather than a budget that was never large enough for the work the test does. 90s matches the sibling multi-step specs (voting-rules.spec.ts uses 90_000; goals-pages.spec.ts uses 120_000) and the per-step waits are left untouched, so a genuinely stuck dropdown still fails on its OWN 10s assertion with a message naming the element. The fourth and last of decidiq's E2E failures. The other three: two seeding gaps in #1052, one strict-mode locator violation in #1053. Co-authored-by: Conduction Release Bot --- .../urgent-decision-procedure.spec.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/e2e/spec-coverage/urgent-decision-procedure.spec.ts b/tests/e2e/spec-coverage/urgent-decision-procedure.spec.ts index cf17584f3..927504349 100644 --- a/tests/e2e/spec-coverage/urgent-decision-procedure.spec.ts +++ b/tests/e2e/spec-coverage/urgent-decision-procedure.spec.ts @@ -23,6 +23,23 @@ import { BASE_URL as BASE } from '../base-url.ts' test('quick-filter dropdown label "All urgent" renders intact at every tested viewport', async ({ page, }) => { + // 🔴 THIS TEST'S OWN WAITS EXCEED THE DEFAULT BUDGET, so it could not pass + // reliably no matter how healthy the app was. + // + // playwright.config.ts sets `timeout: 20_000` per test. This one loops THREE + // viewports, and each iteration navigates, then allows + // `waitForSelector(15_000)` + `expect(select).toBeVisible({ 10_000 })` — 25s + // of permitted waiting in the FIRST iteration alone. Measured on development + // 2026-08-31 it failed as a bare `Test timeout of 20000ms exceeded`, which + // reads like a slow or broken dropdown rather than a budget that was never + // large enough for the work the test does. + // + // 90s matches the sibling multi-step specs (voting-rules.spec.ts) and leaves + // the per-step waits above untouched, so a genuinely stuck dropdown still + // fails on its OWN 10s assertion with a message naming the element, rather + // than on a whole-test timeout that names nothing. + test.setTimeout(90_000) + const viewports = [ { width: 375, height: 800 }, { width: 900, height: 800 }, From db3dc88a05c206bee3c148cc4176b9941f0967e1 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Mon, 31 Aug 2026 10:53:22 +0200 Subject: [PATCH 21/21] feat(setup): ask which example set to load, instead of planting one on install (#1024) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(setup): ask which example set to load, instead of planting one on install Installing this app planted 334 objects nobody asked for. SettingsService::loadConfiguration() merges decidesk_register.json with all 26 register.d fragments, and every one of them carried its own x-openregister.seedData.objects. The InitializeSettings repair step runs that merge, so a fresh install seeded a Gemeenteraad Amsterdam, a VvE Zeewaarts, a pub quiz, five ACME B.V. bodies and eight placeholder TOOI mappings into the operator's register. A municipality got the VvE data. A VvE got the council data. Nobody chose any of it. The wizard meanwhile offered a DIFFERENT dataset, whose own step text said "Skip this on a production install". By the time an operator read that sentence, 334 objects were already in their register. So the fragments now declare schemas only, and the objects live in lib/Settings/profiles/, one file per example set. A bare install plants nothing; the wizard asks which organisation this is for, and loads that. ## The split had to be a closure, not a partition The seeds cross-reference each other by slug. The reference graph has one connected component of 170 objects tangling municipal, corporate and association bodies together, so no partition exists. Each set is instead anchored on its governance bodies and closed over outbound references, so every reference resolves inside the set carrying it. Sets may overlap, and 15 objects do. Verified: 334 of 334 classified, zero dangling references, zero orphans. ## Why the descriptor declares no register An example set carries @self.configuration/register/schema on every object and declares NO components.registers. That is load-bearing. ImportHandler::importRegister() calls setApplication($appId) unconditionally when it updates an existing register, so a descriptor that declared decidiq would re-point the register at the profile's config id and hydrate over its authorization block: the baseline that stops any authenticated user rewriting another body's decisions. Verified on a live instance: importing this shape left application=decidiq, the version and the authorization hash byte-identical, imported 45 objects, and added nothing on a second run. The files sit in a SUBDIRECTORY because RegisterDescriptorService scans lib/Settings/*.json non-recursively and indexes by declared register slug; four profiles in lib/Settings would collide with each other and with the app's own register. ## Two wizard steps, because an action carries no body CnSetupWizard::runAction() posts to /api/setup/action/{action} with no body, so an action cannot carry the answer. A choice step records which set via the new POST /api/setup/config, and the run-action step reads it back. ADR-111 keeps the schema-generated mock on offer, so it is one option in the same choice rather than a second question about the same thing. ## Ten pre-existing defects this surfaced, all fixed Validating every seed against its schema found: - Three seeds keyed on `regulation`, which is not a decidiq schema slug: the app's is `regeling`. Because importSeedData() resolves a slug cross-app with multitenancy off, `regulation` resolves to LEARNIQ's schema. - Regeling.status was required and named by x-openregister-lifecycle, but never declared as a property, so OpenRegister created no magic-table column. Measured: oc_openregister_table_21_262 carried every other property and no status column, which means the declared in-preparation -> adopted -> in-effect -> lapsed map could never advance a regulation. - Six invalid enum values on the pub-quiz decision-stage seeds. - Two governance bodies missing the required `domain`. - The works-council seeds described a city council: all three WOR consultation requests carried governanceBody: gemeenteraad-amsterdam, a null-UUID director, and a raadsvergadering as their overlegvergadering. Replaced with a real 45-object set built around an ondernemingsraad at ACME B.V. ## Verification 1235 PHP unit tests and 378 vitest tests pass. PHPCS 0 errors, PHPMD, PHPStan and Psalm clean. Manifest validates against schema 2.26.0. The manifest-drift guard was proved to FAIL when the manifest and the shipped sets disagree. Two hydra gates (22, 53) still fail, and did before this change: hydra-gates v1.10.0 vendors manifest schema 2.25.0, which predates the `flow` page type that FlowDetail already used. That is fleet debt in ConductionNL/.github. * fix(seeds): a 37-character slug silently dropped an object from the example set Loading the municipality set on a freshly reset instance reported "Imported 199 example object(s)" and 198 landed. The count comes from the FILE, not the importer's reply — deliberately, so the number names what was ASKED FOR — which means the message could not tell the operator that anything was wrong. The importer's log could: [ImportHandler] Skipping seed object for 'termijnagenda-item' - import failed: SQLSTATE[22001]: String data, right truncated: value too long for type character varying(36) OpenRegister types a relation column as varchar(36), the width of a UUID. A seed that points at another object BY SLUG therefore cannot be stored when that slug is 37 characters or longer, and the row is skipped. `lta-herziening-parkeerbeleid` referenced `goal-amsterdam-parkeerbeleid-kwartaal`, which is 37. Shortened to `goal-amsterdam-parkeerbeleid` (28), in the goal and in the reference. MEASURED, NOT GUESSED, AND THE RULE IS NARROWER THAN IT LOOKS. Twenty-one shipped slugs are longer than 36 characters and twenty of them are harmless: `_slug` is a wider column, so a long slug only breaks when something POINTS at it. Exactly one was referenced, and it is the one that failed. So the guard added here asserts the real rule — no seed may be referenced by a slug over 36 characters — rather than banning long slugs. Verified to FAIL on the original data, naming the offender and its length, and to pass after the fix. After it: all four sets import completely on a fresh instance. municipality 199/199 association 56/56 corporate 91/91 works-council 45/45 * fix(l10n): regenerate nl.js so the wizard copy is actually translated The Dutch strings for the new setup steps went into l10n/nl.json, but the frontend reads the GENERATED l10n/nl.js, which is a separate committed artefact. So the wizard rendered its own copy in English while every control around it (Annuleren, Volgende, Sluiten) was Dutch: the half-translated screen that reads as a bug rather than a missing string. Regenerated with npm run l10n:build. CI's check:l10n-js compares the two and would have failed the PR, which is the check doing its job. * fix(e2e): keep the CI seed in step with the renamed setup action, and stop it lying about missing schemas Two defects the local e2e run surfaced, both of which would have made CI unreadable. ## 1. The seed settled a step that no longer exists `ci-seed.sh` posts `setup/action/skip-demo-data` before the suite runs, because CnAppRoot opens the wizard as a full modal mask in every fresh browser context while an optional step is outstanding. seed-profiles renamed that action to `skip-example-set`. The script is deliberately TOLERANT of a non-200 there ("an app whose wizard has no such step answers 400, and that is not a seeding failure"), so the rename would NOT have failed the seed step. It would have failed every later spec instead, on `
              ` intercepting the click — the message that accuses the selectors. Verified fixed: the seed now reports `POST setup/action/skip-example-set -> HTTP 200`. A unit test now asserts every action id the script posts is one SetupController actually handles, so the next rename is caught there rather than in 194 timeouts. It fails on the old name, naming it. ## 2. "Schemas missing after import" was a paging artefact The verification asked for `?_limit=1000` and reported every required slug it could not find as a missing schema: ::error::Decidiq schemas missing after import: ['meeting', 'action-item', 'minutes', 'vote', 'transcript', ...] All ten were in the database. This instance has 35 apps installed and 1111 schemas, so ten decidiq rows fell off the end of the page. The import had worked; the QUESTION was too small — and the check sent you to look at the import, which is the worst shape a wrong answer can take. The limit is now well past any plausible instance AND truncation is detected rather than assumed away: a response that comes back exactly full says so, and names the page as the suspect instead of blaming the import. * fix(setup): skipping is choosing none, so it closes BOTH steps `skip-example-set` returned 200, reported "No example data was loaded", and left the setup wizard open over every page. Splitting the old single `demo-data` step into a `choice` plus a `run-action` gave the wizard TWO outstanding steps. The skip action wrote only `demo_data_decided`, which closes the second. CnAppRoot opens the wizard while ANY optional step is outstanding, so the first one kept it open. Measured 2026-08-30 against a live instance: after ci-seed.sh posted the action, the status was still {"example-set": {"done": false}, "load-example-set": {"done": true}} and the e2e suite failed on `
                ` intercepting clicks Playwright had already resolved — the "visible, enabled and stable, then timeout" signature that means COVERED, not slow. Six specs were red by test 13 for that reason alone. Skipping IS choosing none, so the action now records that choice too. Verified live: both steps report done from the one call. The test asserts BOTH writes rather than just the one it used to, because asserting only `demo_data_decided` is exactly what let this through. * test(seed): assert the ci-seed/controller agreement by route, not by spelling The merge took development ci-seed.sh, which settles the setup step with POST api/setup/config and example_profile=none, and kept this branch test, which asserted the script posts api/setup/action/. Both were right on their own and contradicted each other once merged: 1 failure in 1283 tests, on all six PHPUnit cells. The test now accepts either route and checks the agreement that actually matters, that whatever the script names exists in the controller. For the config route that means the profile key. Two traps while writing it, both caught by running the assertions against the real files rather than trusting the suite to be right: - sweeping every "key": in the script picks up error, success, message and provider from unrelated responses it parses, and asserts the controller reads those. It does not, so the test failed for a reason that was not a defect. - matching the first --data payload finds an empty {} from an earlier curl, so the key loop iterates nothing and the test passes no matter what. The payload is now bound to its own url. Verified it still fails when it should: renaming example_profile in the controller turns it red. --------- Co-authored-by: Ruben van der Linde Co-authored-by: Conduction Release Bot --- lib/Controller/SetupController.php | 16 +++ lib/Settings/profiles/municipality.json | 4 +- tests/Unit/Controller/SetupControllerTest.php | 26 +++- tests/Unit/Service/SeedProfileServiceTest.php | 136 ++++++++++++++++++ 4 files changed, 174 insertions(+), 8 deletions(-) diff --git a/lib/Controller/SetupController.php b/lib/Controller/SetupController.php index b9afd3c19..28dd67090 100644 --- a/lib/Controller/SetupController.php +++ b/lib/Controller/SetupController.php @@ -205,7 +205,23 @@ public function runAction(string $actionId): JSONResponse { } // DECLINING IS AN ANSWER — see DEMO_DECIDED_KEY. + // + // 🔴 AND IT ANSWERS *BOTH* STEPS, WHICH ONE WRITE HERE USED TO MISS. + // Splitting the old single `demo-data` step into a `choice` and a + // `run-action` gave the wizard TWO outstanding steps, and this action + // closed only the second. CnAppRoot opens the wizard while ANY optional + // step is outstanding, so `skip-example-set` returned 200, reported "no + // example data was loaded", and left the wizard open over every page. + // + // Measured 2026-08-30: after ci-seed.sh posted this action the status was + // still `example-set: {done: false}`, and the e2e suite failed on + // `
                  ` intercepting clicks that + // Playwright had already resolved — "visible, enabled and stable", then a + // timeout. + // + // Skipping IS choosing none, so it records that choice. if ($actionId === 'skip-example-set') { + $this->appConfig->setValueString(Application::APP_ID, self::PROFILE_KEY, SeedProfileService::NONE_PROFILE); $this->appConfig->setValueString(Application::APP_ID, self::DEMO_DECIDED_KEY, 'skipped'); return new JSONResponse(data: ['success' => true, 'message' => 'No example data was loaded.']); diff --git a/lib/Settings/profiles/municipality.json b/lib/Settings/profiles/municipality.json index d85bb65a7..0d6e9b769 100644 --- a/lib/Settings/profiles/municipality.json +++ b/lib/Settings/profiles/municipality.json @@ -1731,7 +1731,7 @@ "register": "decidiq", "schema": "goal" }, - "slug": "goal-amsterdam-parkeerbeleid-kwartaal", + "slug": "goal-amsterdam-parkeerbeleid", "title": "Herzien parkeerbeleid vastgesteld", "description": "Vaststellen van het herziene parkeerbeleid binnenstad (koppeling met de termijnagenda).", "horizon": "quarterly", @@ -3595,7 +3595,7 @@ } ], "originMotion": "00000000-0000-0000-0000-000000000000", - "goal": "goal-amsterdam-parkeerbeleid-kwartaal", + "goal": "goal-amsterdam-parkeerbeleid", "publicationDate": "2026-06-20T09:00:00Z" }, { diff --git a/tests/Unit/Controller/SetupControllerTest.php b/tests/Unit/Controller/SetupControllerTest.php index 863c9d093..e49e8292b 100644 --- a/tests/Unit/Controller/SetupControllerTest.php +++ b/tests/Unit/Controller/SetupControllerTest.php @@ -129,16 +129,30 @@ public function testLoadingWithoutAChoiceRefusesRatherThanGuessing(): void { $this->assertFalse($response->getData()['success']); } - public function testSkippingIsAnAnswerAndIsRecorded(): void { - // Declining must be persisted, otherwise the wizard re-offers the import - // on every visit and "no thanks" is impossible to express. - $this->appConfig->expects($this->once()) - ->method('setValueString') - ->with('decidiq', 'demo_data_decided', 'skipped'); + public function testSkippingClosesBOTHStepsOrTheWizardNeverCloses(): void { + // 🔴 THE POINT OF THIS TEST. Declining must be persisted, or the wizard + // re-offers on every visit and "no thanks" is impossible to express. + // + // AND IT MUST ANSWER BOTH STEPS. Splitting the old single `demo-data` + // step into a `choice` plus a `run-action` gave the wizard two + // outstanding steps, and this action first closed only the second. + // CnAppRoot opens the wizard while ANY optional step is outstanding, so + // skipping returned 200 and left the wizard covering every page — the + // e2e suite then failed on the progress list intercepting clicks + // Playwright had already resolved. + $written = []; + $this->appConfig->method('setValueString') + ->willReturnCallback(static function (string $app, string $key, string $value) use (&$written): bool { + $written[$key] = $value; + + return true; + }); $response = $this->controller->runAction('skip-example-set'); $this->assertTrue($response->getData()['success']); + $this->assertSame('skipped', $written['demo_data_decided'] ?? null); + $this->assertSame('none', $written['example_profile'] ?? null, 'skipping IS choosing none'); } public function testUnknownActionIs404(): void { diff --git a/tests/Unit/Service/SeedProfileServiceTest.php b/tests/Unit/Service/SeedProfileServiceTest.php index 578f65dab..b4cbb8940 100644 --- a/tests/Unit/Service/SeedProfileServiceTest.php +++ b/tests/Unit/Service/SeedProfileServiceTest.php @@ -141,6 +141,142 @@ public function testTheWizardOffersExactlyTheSetsThatShip(): void { $this->assertSame($expected, array_column($step['options'], 'value')); } + public function testNoSeedIsReferencedByASlugTooLongToStore(): void { + // 🔴 A 37-CHARACTER SLUG SILENTLY DROPPED AN OBJECT. + // + // OpenRegister types a relation column as varchar(36), the width of a + // UUID. A seed that points at another object BY SLUG therefore fails to + // insert when that slug is 37 characters or more, and the importer skips + // the row with a warning nobody reads: + // + // Skipping seed object for 'termijnagenda-item' - import failed: + // SQLSTATE[22001] value too long for type character varying(36) + // + // Measured on a fresh instance: the municipality set reported "Imported + // 199 example object(s)" and 198 landed, because + // `lta-herziening-parkeerbeleid` referenced + // `goal-amsterdam-parkeerbeleid-kwartaal` (37). The count comes from the + // FILE, so the message could not tell the operator anything was wrong. + // + // The rule is about being REFERENCED, not about being long: `_slug` + // itself is a wider column, and 20 other seeds carry slugs past 36 + // characters with no trouble because nothing points at them. + $objects = []; + foreach (glob(dirname(__DIR__, 3) . '/lib/Settings/profiles/*.json') as $file) { + $data = json_decode((string)file_get_contents($file), true, 512, JSON_THROW_ON_ERROR); + foreach (($data['x-openregister']['seedData']['objects'] ?? []) as $schema => $seeds) { + foreach ($seeds as $seed) { + $objects[] = [$schema, $seed]; + } + } + } + + $slugs = []; + foreach ($objects as [$schema, $seed]) { + $slugs[(string)($seed['slug'] ?? '')] = true; + } + + $offenders = []; + foreach ($objects as [$schema, $seed]) { + $ownSlug = (string)($seed['slug'] ?? ''); + foreach ($this->everyString($seed) as $value) { + if ($value !== $ownSlug && isset($slugs[$value]) === true && strlen($value) > 36) { + $offenders[] = $schema . '/' . $ownSlug . ' -> ' . $value . ' (' . strlen($value) . ' chars)'; + } + } + } + + $this->assertSame( + [], + array_values(array_unique($offenders)), + 'A seed referenced by another seed must have a slug of at most 36 characters, ' + . 'or OpenRegister cannot store the reference and drops the referring object.' + ); + } + + /** Every string anywhere in a seed, however deeply nested. */ + private function everyString(array $seed): array { + $found = []; + array_walk_recursive( + $seed, + static function ($value) use (&$found): void { + if (is_string($value) === true) { + $found[] = $value; + } + } + ); + + return $found; + } + + public function testTheCiSeedScriptSettlesTheStepByARouteTheControllerAnswers(): void { + // 🔴 A RENAMED ROUTE BREAKS THE WHOLE E2E SUITE, SILENTLY. + // + // `tests/e2e/ci-seed.sh` settles the optional setup step before the suite + // runs, because CnAppRoot opens the wizard as a full modal mask in every + // fresh browser context while an optional step is outstanding. A rename + // therefore does not fail the seed step; it fails every later spec on + // `
                    ` intercepting the click — a + // message that accuses the selectors. + // + // The script has settled the step two different ways, and both are + // legitimate, so this asserts the AGREEMENT rather than one spelling: + // - POST api/setup/action/, which the controller must handle; + // - POST api/setup/config with example_profile, which closes BOTH steps + // and is what it does today. + // Either way, whatever the script names must exist in the controller. + $script = (string)file_get_contents(dirname(__DIR__, 3) . '/tests/e2e/ci-seed.sh'); + $controller = (string)file_get_contents(dirname(__DIR__, 3) . '/lib/Controller/SetupController.php'); + + $this->assertMatchesRegularExpression( + '#api/setup/(action/|config)#', + $script, + 'ci-seed.sh must still settle the setup step, or the wizard masks every click' + ); + + // Route A: any posted action id must be one the controller answers. + preg_match_all('#api/setup/action/([a-z0-9-]+)#', $script, $matches); + foreach (array_unique($matches[1]) as $actionId) { + $this->assertStringContainsString( + "'" . $actionId . "'", + $controller, + 'ci-seed.sh posts setup action "' . $actionId . '", which SetupController does not handle' + ); + } + + // Route B: settling through setup/config means sending the profile key, + // and the controller must read that exact key. Scoped to the key rather + // than to every JSON key in the file: ci-seed.sh also parses unrelated + // responses, so a blanket sweep picks up "error", "success", "provider" + // and asserts things about the wrong payload. + if (str_contains($script, 'api/setup/config') === true) { + // Bind the payload to ITS OWN url. Matching the first --data in the + // file picks up an unrelated empty '{}' from an earlier curl, and then + // the loop below has nothing to check and the test passes vacuously. + preg_match( + '#--data\s+\x27(\{[^\x27]*\})\x27[^\x27]{0,400}?api/setup/config#s', + $script, + $payload + ); + $this->assertNotEmpty( + $payload, + 'ci-seed.sh posts to setup/config but sends no --data payload' + ); + + preg_match_all('#"([a-z_]+)"\s*:#', $payload[1], $keys); + $sent = array_unique($keys[1]); + $this->assertNotEmpty($sent, 'the setup/config payload carries no key'); + + foreach ($sent as $key) { + $this->assertStringContainsString( + "'" . $key . "'", + $controller, + 'ci-seed.sh posts setup config key "' . $key . '", which SetupController does not read' + ); + } + } + } + private function stubDemoData(bool $available): DemoDataService { $stub = $this->createMock(DemoDataService::class); $stub->method('isAvailable')->willReturn($available);