From ef20f725aa9b6f63d3a620b3682d1a18a0d5b47a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2026 20:21:11 +0000 Subject: [PATCH 1/4] chore(deps-dev): bump vitest from 4.1.11 to 5.0.0 Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 4.1.11 to 5.0.0. - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md) - [Commits](https://github.com/vitest-dev/vitest/commits/v5.0.0/packages/vitest) --- updated-dependencies: - dependency-name: vitest dependency-version: 5.0.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package-lock.json | 176 ++++++++++++---------------------------------- package.json | 2 +- 2 files changed, 45 insertions(+), 133 deletions(-) diff --git a/package-lock.json b/package-lock.json index f1c9e85..a9eb1fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,7 @@ "stylelint": "^17.9.1", "typescript": "^6.0.3", "vite": "^8.2.2", - "vitest": "^4.1.4", + "vitest": "^5.0.0", "vue-tsc": "^3.3.11" }, "engines": { @@ -2264,13 +2264,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "dev": true, - "license": "MIT" - }, "node_modules/@stylistic/eslint-plugin": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.10.0.tgz", @@ -2749,34 +2742,17 @@ } } }, - "node_modules/@vitest/expect": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz", - "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.1.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.11", - "@vitest/utils": "4.1.11", - "chai": "^6.2.2", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, "node_modules/@vitest/mocker": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz", - "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-5.0.0.tgz", + "integrity": "sha512-66PGTMIiVJP3t4a5yxU9qPtf7MdTBs8jmToMvy+HVflB3Yy13WJZTtPePdvU+wjRV02SKK5doLbSA6o9pwOmiA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.11", + "@jridgewell/trace-mapping": "0.3.31", + "@vitest/spy": "5.0.0", "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" + "magic-string": "^1.2.3" }, "funding": { "url": "https://opencollective.com/vitest" @@ -2804,16 +2780,6 @@ "@types/estree": "^1.0.0" } }, - "node_modules/@vitest/mocker/node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, "node_modules/@vitest/pretty-format": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz", @@ -2827,50 +2793,10 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/runner": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz", - "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.1.11", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz", - "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.11", - "@vitest/utils": "4.1.11", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot/node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, "node_modules/@vitest/spy": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz", - "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-5.0.0.tgz", + "integrity": "sha512-uy+luWBAPw9XfthoHi5AkfHUnuPYEESjl0p/r+meoBnU8bxg5GDQ3Ey8MjcJ6sqahkL4PFyrvfMJJBw7LbU06g==", "dev": true, "license": "MIT", "funding": { @@ -10944,16 +10870,19 @@ } }, "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-6.1.4.tgz", + "integrity": "sha512-9APumHG7r4yOk4X4WlkmE71aZcv1gvin1czO3OQ1U9iJcFA5Ja/ygyb0vPOVHTthFozUYs8CLoLUlM8grb2lTQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } }, "node_modules/tinyexec": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", - "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.0.tgz", + "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==", "dev": true, "license": "MIT", "engines": { @@ -11628,38 +11557,31 @@ } }, "node_modules/vitest": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz", - "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-5.0.0.tgz", + "integrity": "sha512-gpsMNoRhMjMktVxPtstOH4/PJuPyovVaMDr4oDilXaGH1EcqM2OE96SoHT2VIQ6fTGtTjqmHDrEu2X9RQiXf8Q==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.11", - "@vitest/mocker": "4.1.11", - "@vitest/pretty-format": "4.1.11", - "@vitest/runner": "4.1.11", - "@vitest/snapshot": "4.1.11", - "@vitest/spy": "4.1.11", - "@vitest/utils": "4.1.11", - "es-module-lexer": "^2.0.0", - "expect-type": "^1.3.0", - "magic-string": "^0.30.21", - "obug": "^2.1.1", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "std-env": "^4.0.0-rc.1", - "tinybench": "^2.9.0", - "tinyexec": "^1.0.2", - "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.1.0", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "@types/chai": "^5.2.2", + "@vitest/mocker": "5.0.0", + "chai": "^6.2.2", + "es-module-lexer": "^2.3.2", + "expect-type": "^1.4.0", + "magic-string": "^1.2.3", + "obug": "^2.1.4", + "picomatch": "^4.0.7", + "std-env": "^4.2.0", + "tinybench": "6.1.4", + "tinyexec": "1.3.0", + "tinyglobby": "^0.2.17", "why-is-node-running": "^2.3.0" }, "bin": { "vitest": "vitest.mjs" }, "engines": { - "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + "node": "^22.12.0 || ^24.0.0 || >=26.0.0" }, "funding": { "url": "https://opencollective.com/vitest" @@ -11667,16 +11589,16 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", - "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.11", - "@vitest/browser-preview": "4.1.11", - "@vitest/browser-webdriverio": "4.1.11", - "@vitest/coverage-istanbul": "4.1.11", - "@vitest/coverage-v8": "4.1.11", - "@vitest/ui": "4.1.11", + "@types/node": "^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "5.0.0", + "@vitest/browser-preview": "5.0.0", + "@vitest/browser-webdriverio": "^5.0.0-beta.5 || >=5.0.0", + "@vitest/coverage-istanbul": "5.0.0", + "@vitest/coverage-v8": "5.0.0", + "@vitest/ui": "5.0.0", "happy-dom": "*", "jsdom": "*", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + "vite": "^6.4.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "@edge-runtime/vm": { @@ -11717,16 +11639,6 @@ } } }, - "node_modules/vitest/node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, "node_modules/vm-browserify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", diff --git a/package.json b/package.json index 2791c4e..a94321b 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "stylelint": "^17.9.1", "typescript": "^6.0.3", "vite": "^8.2.2", - "vitest": "^4.1.4", + "vitest": "^5.0.0", "vue-tsc": "^3.3.11" }, "engines": { From 19b582f82bb3787108ea8bab78694781daa2fbe8 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Fri, 2 Oct 2026 15:16:19 -0300 Subject: [PATCH 2/4] fix(deps): align Vitest coverage with Vitest 5 --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a94321b..5954945 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "@nextcloud/axios": "^2.6.0", "@nextcloud/l10n": "^3.4.1", "@nextcloud/router": "^3.1.0", - "@nextcloud/vue": "^9.11.0", + "@nextcloud/vue": "^9.13.1", "vue": "^3.5.30" }, "devDependencies": { @@ -39,15 +39,15 @@ "@nextcloud/stylelint-config": "^3.2.1", "@nextcloud/vite-config": "^3.0.0-beta.1", "@playwright/test": "^1.62.1", - "@types/node": "^24.0.0", - "@vitejs/plugin-vue": "^6.0.8", - "@vitest/coverage-v8": "^4.1.11", + "@types/node": "^26.5.1", + "@vitejs/plugin-vue": "^6.0.9", + "@vitest/coverage-v8": "^5.0.0", "@vue/test-utils": "^2.5.0", "happy-dom": "^20.14.0", "openapi-typescript": "^7.13.0", "stylelint": "^17.9.1", "typescript": "^6.0.3", - "vite": "^8.2.2", + "vite": "^8.3.0", "vitest": "^5.0.0", "vue-tsc": "^3.3.11" }, From b39ffe50174735c9e07c43461f545622a6eb8814 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Fri, 2 Oct 2026 15:16:22 -0300 Subject: [PATCH 3/4] chore(deps): refresh lockfile for Vitest 5 --- package-lock.json | 363 ++++++++++++++++++++++++++-------------------- 1 file changed, 209 insertions(+), 154 deletions(-) diff --git a/package-lock.json b/package-lock.json index a9eb1fa..df4efa8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@nextcloud/axios": "^2.6.0", "@nextcloud/l10n": "^3.4.1", "@nextcloud/router": "^3.1.0", - "@nextcloud/vue": "^9.11.0", + "@nextcloud/vue": "^9.13.1", "vue": "^3.5.30" }, "devDependencies": { @@ -21,15 +21,15 @@ "@nextcloud/stylelint-config": "^3.2.1", "@nextcloud/vite-config": "^3.0.0-beta.1", "@playwright/test": "^1.62.1", - "@types/node": "^24.0.0", - "@vitejs/plugin-vue": "^6.0.8", - "@vitest/coverage-v8": "^4.1.11", + "@types/node": "^26.5.1", + "@vitejs/plugin-vue": "^6.0.9", + "@vitest/coverage-v8": "^5.0.0", "@vue/test-utils": "^2.5.0", "happy-dom": "^20.14.0", "openapi-typescript": "^7.13.0", "stylelint": "^17.9.1", "typescript": "^6.0.3", - "vite": "^8.2.2", + "vite": "^8.3.0", "vitest": "^5.0.0", "vue-tsc": "^3.3.11" }, @@ -733,6 +733,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -847,65 +848,28 @@ } }, "node_modules/@nextcloud/files": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@nextcloud/files/-/files-4.0.0.tgz", - "integrity": "sha512-TmecnZIS+PGWGtRh7RpGEboCT4K6iTbHULUcfR6hs3eEzjDVsCc1Ldf8popGY/70lbpdlfYle8xbXnPIo3qaXA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@nextcloud/files/-/files-4.1.0.tgz", + "integrity": "sha512-C45fxBxU9v5HQ437I+r4EuqG/A9CYqNnYM34ltdxFNSBMjId7DoRJrk5UDA7QsC4eB/CP1xNxFSpkY+g6RPWXA==", "license": "AGPL-3.0-or-later", "optional": true, "dependencies": { - "@nextcloud/auth": "^2.5.3", + "@nextcloud/auth": "^2.6.0", + "@nextcloud/axios": "^2.6.0", "@nextcloud/capabilities": "^1.2.1", "@nextcloud/l10n": "^3.4.1", "@nextcloud/logger": "^3.0.3", - "@nextcloud/paths": "^3.0.0", + "@nextcloud/paths": "^3.1.0", "@nextcloud/router": "^3.1.0", - "@nextcloud/sharing": "^0.3.0", + "@nextcloud/sharing": "^0.4.0", + "axios-retry": "^4.5.0", "is-svg": "^6.1.0", + "p-queue": "^9.3.3", "typescript-event-target": "^1.1.2", - "webdav": "^5.9.0" - }, - "engines": { - "node": "^24.0.0" - } - }, - "node_modules/@nextcloud/files/node_modules/@nextcloud/files": { - "version": "3.12.2", - "resolved": "https://registry.npmjs.org/@nextcloud/files/-/files-3.12.2.tgz", - "integrity": "sha512-vBo8tf3Xh6efiF8CrEo3pKj9AtvAF6RdDGO1XKL65IxV8+UUd9Uxl2lUExHlzoDRRczCqfGfaWfRRaFhYqce5Q==", - "license": "AGPL-3.0-or-later", - "optional": true, - "dependencies": { - "@nextcloud/auth": "^2.5.3", - "@nextcloud/capabilities": "^1.2.1", - "@nextcloud/l10n": "^3.4.1", - "@nextcloud/logger": "^3.0.3", - "@nextcloud/paths": "^3.0.0", - "@nextcloud/router": "^3.1.0", - "@nextcloud/sharing": "^0.3.0", - "cancelable-promise": "^4.3.1", - "is-svg": "^6.1.0", - "typescript-event-target": "^1.1.1", - "webdav": "^5.8.0" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || ^24.0.0" - } - }, - "node_modules/@nextcloud/files/node_modules/@nextcloud/sharing": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@nextcloud/sharing/-/sharing-0.3.0.tgz", - "integrity": "sha512-kV7qeUZvd1fTKeFyH+W5Qq5rNOqG9rLATZM3U9MBxWXHJs3OxMqYQb8UQ3NYONzsX3zDGJmdQECIGHm1ei2sCA==", - "license": "GPL-3.0-or-later", - "optional": true, - "dependencies": { - "@nextcloud/initial-state": "^3.0.0", - "is-svg": "^6.1.0" + "webdav": "^5.10.0" }, "engines": { - "node": "^20.0.0 || ^22.0.0 || ^24.0.0" - }, - "optionalDependencies": { - "@nextcloud/files": "^3.12.0" + "node": "^24.0.0 || >=26.0.0" } }, "node_modules/@nextcloud/initial-state": { @@ -956,9 +920,9 @@ } }, "node_modules/@nextcloud/router": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-3.1.0.tgz", - "integrity": "sha512-e4dkIaxRSwdZJlZFpn9x03QgBn/Sa2hN1hp/BA7+AbzykmSAlKuWfdmX8j/8ewrLpQwYmZR23IZO9XwpJXq2Uw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-3.2.0.tgz", + "integrity": "sha512-an4gJ7mlDZGtYq8zTxp4Sg+iLlKKGvQ9ZH3Dp6ga/IlDNAP7VeMVGphsY798ORjncAp9+sEf370L5zpsnuxgng==", "license": "GPL-3.0-or-later", "dependencies": { "@nextcloud/typings": "^1.10.0" @@ -1040,9 +1004,9 @@ } }, "node_modules/@nextcloud/vue": { - "version": "9.11.0", - "resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-9.11.0.tgz", - "integrity": "sha512-LRsyU9Mxs0b2xWqbxygps8O7/i1z4QhNQD9/QDni+VqFY3V0N95mAgmKJm6vfoFuxTAMXERp9bjqFn3UV542gw==", + "version": "9.13.1", + "resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-9.13.1.tgz", + "integrity": "sha512-6ZeHm+coHJ6wsavulll4CVl3tk5ehjh7p6pW9GU1BgfDkOsbx5Pv4U8/uVk7yOTn4oAo695XTHhFN17pyI1peQ==", "license": "AGPL-3.0-or-later", "dependencies": { "@ckpack/vue-color": "^1.6.0", @@ -1055,7 +1019,7 @@ "@nextcloud/initial-state": "^3.0.0", "@nextcloud/l10n": "^3.4.1", "@nextcloud/logger": "^3.0.3", - "@nextcloud/router": "^3.1.0", + "@nextcloud/router": "^3.2.0", "@nextcloud/sharing": "^0.4.0", "@nextcloud/vue-select": "^4.1.0", "@vuepic/vue-datepicker": "^11.0.3", @@ -1064,7 +1028,7 @@ "blurhash": "^2.0.5", "clone": "^2.1.2", "debounce": "^3.0.0", - "dompurify": "^3.4.14", + "dompurify": "^3.4.15", "emoji-mart-vue-fast": "^15.0.5", "escape-html": "^1.0.3", "floating-vue": "^5.2.2", @@ -1088,10 +1052,22 @@ "unist-builder": "^4.0.0", "unist-util-visit-parents": "^6.0.2", "vue": "^3.5.18", - "vue-router": "^5.2.0" + "vue-router": "^5.3.1" }, "engines": { "node": "^20.11.0 || ^22 || ^24" + }, + "peerDependencies": { + "@nextcloud/dialogs": "^7.4.0", + "@nextcloud/files": "^4.1.0" + }, + "peerDependenciesMeta": { + "@nextcloud/dialogs": { + "optional": true + }, + "@nextcloud/files": { + "optional": true + } } }, "node_modules/@nextcloud/vue-select": { @@ -1178,6 +1154,7 @@ "version": "2.6.0", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.6.0.tgz", "integrity": "sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -1217,6 +1194,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1238,6 +1216,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1259,6 +1238,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1280,6 +1260,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1301,6 +1282,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1322,6 +1304,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1343,6 +1326,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1364,6 +1348,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1385,6 +1370,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1406,6 +1392,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1427,6 +1414,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1448,6 +1436,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1510,9 +1499,9 @@ "license": "MIT" }, "node_modules/@redocly/openapi-core": { - "version": "1.34.19", - "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.34.19.tgz", - "integrity": "sha512-o/0VgsBXgwcY1lyeqcVtSGdTQAPnVggo0fbFVPlxl5XVDKUcVH0OLRqt3CbkwByT5FU305E0iE0O7MzThjDblw==", + "version": "1.34.20", + "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.34.20.tgz", + "integrity": "sha512-ypeBZ/6BKXR9+7/TtbKhbl4UgD7raHhPS12oknlKno2A8+lnFkxIwiE/Aklu6L2cd/ioH+fCWuMxi9/p3EyAPw==", "dev": true, "license": "MIT", "dependencies": { @@ -1521,7 +1510,7 @@ "colorette": "1.4.0", "https-proxy-agent": "7.0.6", "js-levenshtein": "1.1.6", - "js-yaml": "4.3.1", + "js-yaml": "4.3.2", "minimatch": "5.1.9", "pluralize": "8.0.0", "yaml-ast-parser": "0.0.43" @@ -1549,9 +1538,9 @@ "license": "MIT" }, "node_modules/@redocly/openapi-core/node_modules/brace-expansion": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", - "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", + "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", "dev": true, "license": "MIT", "dependencies": { @@ -1592,6 +1581,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1608,6 +1598,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1624,6 +1615,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1640,6 +1632,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1656,6 +1649,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1672,6 +1666,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1688,6 +1683,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1704,6 +1700,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1720,6 +1717,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1736,6 +1734,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1752,6 +1751,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1768,6 +1768,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1784,6 +1785,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1800,6 +1802,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1816,6 +1819,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1895,6 +1899,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1909,6 +1914,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1923,6 +1929,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1937,6 +1944,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1951,6 +1959,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1965,6 +1974,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1979,6 +1989,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1993,6 +2004,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2007,6 +2019,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2021,6 +2034,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2035,6 +2049,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2049,6 +2064,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2063,6 +2079,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2077,6 +2094,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2091,6 +2109,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2105,6 +2124,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2119,6 +2139,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2133,6 +2154,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2147,6 +2169,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2161,6 +2184,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2175,6 +2199,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2189,6 +2214,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2203,6 +2229,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2217,6 +2244,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2231,6 +2259,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2388,13 +2417,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.13.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz", - "integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==", - "devOptional": true, + "version": "26.5.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.5.1.tgz", + "integrity": "sha512-CzNm2FezW4VR/LjG6yUdiEgLE/rAQ9Slj5gCu/C2VrdcW7I0ahNZ8DRbHT7zOZ6r3ONgd/bsQIeSaoDGrd1C6g==", + "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.18.0" + "undici-types": "~8.9.0" } }, "node_modules/@types/semver": { @@ -2695,9 +2724,9 @@ "license": "ISC" }, "node_modules/@vitejs/plugin-vue": { - "version": "6.0.8", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.8.tgz", - "integrity": "sha512-0ZjgOg7oO6farnNGup7yvoM/YXZV84OZxHAwtflItNa/6zzQyVb5LNxyea3FEKEX2XlagIKzrlH7wwxkKgtiew==", + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.9.tgz", + "integrity": "sha512-rD/MORlhaZMlXWW0rEn4FB4wMinWC0z/D7Ye160S5+Rs1mC8ZDAdcDp4SjKfUhG5t8q1ktcPVw4xuTkPRlzrSA==", "dev": true, "license": "MIT", "dependencies": { @@ -2712,29 +2741,27 @@ } }, "node_modules/@vitest/coverage-v8": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.11.tgz", - "integrity": "sha512-8MVGEFnJIcdGjcbfKmeq8z0pZHH0JlVtoVZH9Q/qwUp6wyFnEJUBMrw9DCaj+ra3vShGmhavjalMIhPNxZAUcw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-5.0.0.tgz", + "integrity": "sha512-toMg6PZGCIa/lQNCDoASrfb1ly4hsUKXFtFYC9kD4t78o5Y6LyNJU7AENt8eHPr3quYdxaxK7hj2mnbFfUk9NA==", "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.1.11", - "ast-v8-to-istanbul": "^1.0.0", - "istanbul-lib-coverage": "^3.2.2", - "istanbul-lib-report": "^3.0.1", - "istanbul-reports": "^3.2.0", - "magicast": "^0.5.2", - "obug": "^2.1.1", - "std-env": "^4.0.0-rc.1", - "tinyrainbow": "^3.1.0" + "@vitest/istanbul-lib-coverage": "^1.0.0", + "@vitest/istanbul-lib-report": "^1.0.0", + "ast-v8-to-istanbul": "^1.0.5", + "magicast": "^0.5.4", + "obug": "^2.1.4", + "std-env": "^4.2.0", + "tinyrainbow": "^3.1.1" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "4.1.11", - "vitest": "4.1.11" + "@vitest/browser": "5.0.0", + "vitest": "5.0.0" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -2742,6 +2769,29 @@ } } }, + "node_modules/@vitest/istanbul-lib-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@vitest/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.1.tgz", + "integrity": "sha512-k3DJZ8LhMBK9NS4SclF1ASD3OgXEWDorbIcPTRDK0/Zae6fRvu+fJRxtFdLfHsa9Y24beCdPnoNZ4LviTNstfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" + } + }, + "node_modules/@vitest/istanbul-lib-report": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@vitest/istanbul-lib-report/-/istanbul-lib-report-1.0.1.tgz", + "integrity": "sha512-1EOLRfsTMnyAr3+kEAsP4o9dhaDlGPpD7H5iLBBeq//YpNB1VIahkPhB+eRp9N2Dkfw8oySROjE3yf9XDeaIkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/istanbul-lib-coverage": "1.0.1" + }, + "engines": { + "node": ">=22" + } + }, "node_modules/@vitest/mocker": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-5.0.0.tgz", @@ -2780,19 +2830,6 @@ "@types/estree": "^1.0.0" } }, - "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/spy": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-5.0.0.tgz", @@ -2803,21 +2840,6 @@ "url": "https://opencollective.com/vitest" } }, - "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/@volar/language-core": { "version": "2.4.28", "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", @@ -3734,6 +3756,19 @@ "proxy-from-env": "^2.1.0" } }, + "node_modules/axios-retry": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-4.5.0.tgz", + "integrity": "sha512-aR99oXhpEDGo0UuAlYcn2iGRds30k366Zfa05XWScR9QaQD4JYiP3/1Qt1u7YlefUOK+cn0CcwoL1oefavQUlQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "is-retry-allowed": "^2.2.0" + }, + "peerDependencies": { + "axios": "0.x || 1.x" + } + }, "node_modules/bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", @@ -3825,9 +3860,9 @@ "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==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4185,13 +4220,6 @@ "node": ">=6" } }, - "node_modules/cancelable-promise": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/cancelable-promise/-/cancelable-promise-4.3.1.tgz", - "integrity": "sha512-A/8PwLk/T7IJDfUdQ68NR24QHa8rIlnN/stiJEBo6dmVUkD4K14LswG0w3VwdeK/o7qOwRUR1k2MhK5Rpy2m7A==", - "license": "MIT", - "optional": true - }, "node_modules/caniuse-lite": { "version": "1.0.30001810", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", @@ -5938,6 +5966,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -6537,7 +6566,7 @@ "version": "5.1.9", "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.9.tgz", "integrity": "sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg==", - "devOptional": true, + "dev": true, "license": "MIT", "peer": true }, @@ -6723,7 +6752,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6763,7 +6792,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -6864,6 +6893,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-retry-allowed": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", + "integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-svg": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-6.1.0.tgz", @@ -7018,9 +7060,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": [ { @@ -7159,6 +7201,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7179,6 +7222,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7199,6 +7243,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7219,6 +7264,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7239,6 +7285,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7259,6 +7306,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7279,6 +7327,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7299,6 +7348,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7319,6 +7369,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7339,6 +7390,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7359,6 +7411,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -8449,6 +8502,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, "license": "MIT", "optional": true, "peer": true @@ -9977,7 +10031,7 @@ "version": "1.104.0", "resolved": "https://registry.npmjs.org/sass/-/sass-1.104.0.tgz", "integrity": "sha512-btHMApW2bgolvClhRW8AlQJzgI9lUB3pPSofBQQT+E46GWvf9o0TVQ13SYv5riWZVFyPN+JNz3TKW9XhBlc10w==", - "devOptional": true, + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -11108,10 +11162,10 @@ "license": "MIT" }, "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", - "devOptional": true, + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", + "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", + "dev": true, "license": "MIT" }, "node_modules/unicorn-magic": { @@ -11452,16 +11506,16 @@ } }, "node_modules/vite": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz", - "integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.0.tgz", + "integrity": "sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ==", "devOptional": true, "license": "MIT", "dependencies": { "lightningcss": "^1.33.0", - "picomatch": "^4.0.5", - "postcss": "^8.5.26", - "rolldown": "~1.2.4", + "picomatch": "^4.0.7", + "postcss": "^8.5.28", + "rolldown": "~1.2.6", "tinyglobby": "^0.2.17" }, "bin": { @@ -11478,7 +11532,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.4.0 || ^0.5.0", + "@vitejs/devtools": "^0.7.1", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -11800,17 +11854,18 @@ } }, "node_modules/webdav": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/webdav/-/webdav-5.10.0.tgz", - "integrity": "sha512-fVPuRLtcduVGvSO7Tn/6TQCzIvI/g6BO/+xPRctCvi/GytYpjn4czxWbh4HsArsdom9qz9BI63k9/v2HBUui1A==", + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/webdav/-/webdav-5.11.0.tgz", + "integrity": "sha512-DbUS8rHvWse55EiHM0q5q1z3eVRCLWW7Va7mUqA2/JJdQHIew4Op2HTglHkBJDOAVrQeQf0I+REUJkIrYqtL+w==", "license": "MIT", "optional": true, "dependencies": { "@buttercup/fetch": "^0.2.1", + "@nodable/entities": "^3.0.0", "base-64": "^1.0.0", "byte-length": "^1.0.2", "entities": "^6.0.1", - "fast-xml-parser": "^5.7.2", + "fast-xml-parser": "^5.11.1", "hot-patcher": "^2.0.1", "layerr": "^3.0.0", "md5": "^2.3.0", @@ -11833,9 +11888,9 @@ "optional": true }, "node_modules/webdav/node_modules/brace-expansion": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", - "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", + "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", "license": "MIT", "optional": true, "dependencies": { From c2f00422c5d2cfc56669a51c9036dbdec99d7dd2 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Fri, 2 Oct 2026 15:17:10 -0300 Subject: [PATCH 4/4] chore(deps): reconcile Vitest 5 update with main --- .github/workflows/openapi.yml | 11 +- REUSE.toml | 3 + docs/protocol-v1.md | 7 + lib/Controller/OcsReportController.php | 83 + lib/Controller/ReportController.php | 28 +- lib/Service/ReportSubmissionService.php | 47 + openapi-administration.json | 1544 +++++++++++++ openapi-full.json | 2000 +++++++++++++++++ openapi.json | 508 +++++ src/types/openapi/openapi-administration.ts | 728 ++++++ src/types/openapi/openapi-full.ts | 944 ++++++++ src/types/openapi/openapi.ts | 243 ++ .../features/api/usage_statistics.feature | 39 +- .../Service/ReportSubmissionServiceTest.php | 120 + vendor-bin/phpstan/composer.json | 2 +- vendor-bin/psalm/composer.json | 2 +- 16 files changed, 6277 insertions(+), 32 deletions(-) create mode 100644 lib/Controller/OcsReportController.php create mode 100644 lib/Service/ReportSubmissionService.php create mode 100644 openapi-administration.json create mode 100644 openapi-full.json create mode 100644 openapi.json create mode 100644 src/types/openapi/openapi-administration.ts create mode 100644 src/types/openapi/openapi-full.ts create mode 100644 src/types/openapi/openapi.ts create mode 100644 tests/php/Integration/Service/ReportSubmissionServiceTest.php diff --git a/.github/workflows/openapi.yml b/.github/workflows/openapi.yml index d8f2c92..7daa86a 100644 --- a/.github/workflows/openapi.yml +++ b/.github/workflows/openapi.yml @@ -56,7 +56,7 @@ jobs: run: npm i -g 'npm@${{ steps.node_versions.outputs.npmVersion }}' - name: Install JavaScript dependencies - run: npm install --no-package-lock + run: npm ci - name: Install Composer dependencies uses: ramsey/composer-install@65e4f84970763564f46a70b8a54b90d033b3bdda # v4.0.0 @@ -73,3 +73,12 @@ jobs: openapi-administration.json openapi-full.json src/types/openapi/*.ts + + - name: Check generated OpenAPI files + run: | + if [[ -n "$(git status --porcelain -- openapi.json openapi-administration.json openapi-full.json src/types/openapi)" ]]; then + echo 'Generated OpenAPI files are out of date. Run "composer run openapi" and commit the generated files.' + git status --short -- openapi.json openapi-administration.json openapi-full.json src/types/openapi + git --no-pager diff -- openapi.json openapi-administration.json openapi-full.json src/types/openapi + exit 1 + fi diff --git a/REUSE.toml b/REUSE.toml index 15928ba..2eb0f59 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -17,6 +17,9 @@ path = [ "package-lock.json", "phpstan.neon", "psalm.xml", + "src/types/openapi/openapi-administration.ts", + "src/types/openapi/openapi-full.ts", + "src/types/openapi/openapi.ts", "tests/integration/composer.json", "tests/integration/composer.lock", "tests/integration/features/api/schema_aggregation.feature", diff --git a/docs/protocol-v1.md b/docs/protocol-v1.md index 7b608bc..b933461 100644 --- a/docs/protocol-v1.md +++ b/docs/protocol-v1.md @@ -21,6 +21,13 @@ Recommended endpoint shape: POST /api/v1/reports ``` +The reference Nextcloud implementation exposes two equivalent ingestion routes: + +- a plain HTTP/JSON route for protocol clients; +- an OCS route for Nextcloud-native tooling and API discovery. + +Both accept the same Protocol v1 request fields. The plain route returns the Protocol v1 response body directly. The OCS route wraps the same application-level response in the standard Nextcloud OCS envelope. OCS is an implementation detail of the Nextcloud reference server and is not required by Protocol v1. + The server SHOULD support idempotent resubmission of the same logical report. A successful submission, including an idempotent retry, returns the same application-level response: diff --git a/lib/Controller/OcsReportController.php b/lib/Controller/OcsReportController.php new file mode 100644 index 0000000..1d94ec2 --- /dev/null +++ b/lib/Controller/OcsReportController.php @@ -0,0 +1,83 @@ + $metrics Aggregate metric values + * + * @return DataResponse|DataResponse + * + * 200: Report accepted + * 400: Invalid report + * 409: Conflicting report for the reporting period + */ + #[PublicPage] + #[NoCSRFRequired] + #[AnonRateLimit(limit: 60, period: 3600)] + #[ApiRoute(verb: 'POST', url: '/api/{apiVersion}/reports', requirements: ['apiVersion' => '(v1)'])] + public function create( + int $protocolVersion, + string $application, + string $installationId, + int $schemaVersion, + array $period, + array $metrics, + ): DataResponse { + try { + $this->submission->submit([ + 'protocolVersion' => $protocolVersion, + 'application' => $application, + 'installationId' => $installationId, + 'schemaVersion' => $schemaVersion, + 'period' => $period, + 'metrics' => $metrics, + ]); + } catch (InvalidReport $e) { + return new DataResponse(['error' => 'invalid_report', 'message' => $e->getMessage()], Http::STATUS_BAD_REQUEST); + } catch (ConflictingReport $e) { + return new DataResponse(['error' => 'conflicting_report', 'message' => $e->getMessage()], Http::STATUS_CONFLICT); + } + + return new DataResponse(['status' => 'accepted'], Http::STATUS_OK); + } +} diff --git a/lib/Controller/ReportController.php b/lib/Controller/ReportController.php index 1a7aee0..3570207 100644 --- a/lib/Controller/ReportController.php +++ b/lib/Controller/ReportController.php @@ -9,37 +9,31 @@ namespace OCA\UsageStatisticsServer\Controller; -use OCA\UsageStatisticsServer\Db\ReportRepository; -use OCA\UsageStatisticsServer\Db\SchemaRepository; use OCA\UsageStatisticsServer\Service\ConflictingReport; use OCA\UsageStatisticsServer\Service\InvalidReport; -use OCA\UsageStatisticsServer\Service\ReportFactory; -use OCA\UsageStatisticsServer\Service\SchemaValidator; +use OCA\UsageStatisticsServer\Service\ReportSubmissionService; +use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Attribute\AnonRateLimit; -use OCP\AppFramework\Http\Attribute\ApiRoute; +use OCP\AppFramework\Http\Attribute\FrontpageRoute; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\Attribute\OpenAPI; use OCP\AppFramework\Http\Attribute\PublicPage; use OCP\AppFramework\Http\DataResponse; -use OCP\AppFramework\OCSController; use OCP\IRequest; #[OpenAPI(tags: ['reports'])] -final class ReportController extends OCSController { +final class ReportController extends Controller { public function __construct( string $appName, IRequest $request, - private readonly ReportFactory $factory, - private readonly ReportRepository $repository, - private readonly SchemaRepository $schemas, - private readonly SchemaValidator $schemaValidator, + private readonly ReportSubmissionService $submission, ) { parent::__construct($appName, $request); } /** - * Submit a usage statistics report + * Submit a usage statistics report as plain Protocol v1 JSON * * Stores one validated report for one application installation and reporting period. * Repeating an already accepted report with the same schema version is idempotent. @@ -60,7 +54,7 @@ public function __construct( #[PublicPage] #[NoCSRFRequired] #[AnonRateLimit(limit: 60, period: 3600)] - #[ApiRoute(verb: 'POST', url: '/api/{apiVersion}/reports', requirements: ['apiVersion' => '(v1)'])] + #[FrontpageRoute(verb: 'POST', url: '/api/{apiVersion}/reports', requirements: ['apiVersion' => '(v1)'])] public function create( int $protocolVersion, string $application, @@ -70,7 +64,7 @@ public function create( array $metrics, ): DataResponse { try { - $report = $this->factory->fromPayload([ + $this->submission->submit([ 'protocolVersion' => $protocolVersion, 'application' => $application, 'installationId' => $installationId, @@ -78,12 +72,6 @@ public function create( 'period' => $period, 'metrics' => $metrics, ]); - $schema = $this->schemas->find($report->application, $report->schemaVersion); - if ($schema === null) { - throw new InvalidReport('Application schema is not registered.'); - } - $this->schemaValidator->validateReport($report, $schema); - $this->repository->store($report); } catch (InvalidReport $e) { return new DataResponse(['error' => 'invalid_report', 'message' => $e->getMessage()], Http::STATUS_BAD_REQUEST); } catch (ConflictingReport $e) { diff --git a/lib/Service/ReportSubmissionService.php b/lib/Service/ReportSubmissionService.php new file mode 100644 index 0000000..1854283 --- /dev/null +++ b/lib/Service/ReportSubmissionService.php @@ -0,0 +1,47 @@ + + * } $payload + * + * @throws InvalidReport + * @throws ConflictingReport + */ + public function submit(array $payload): void { + $report = $this->factory->fromPayload($payload); + $schema = $this->schemas->find($report->application, $report->schemaVersion); + if ($schema === null) { + throw new InvalidReport('Application schema is not registered.'); + } + + $this->schemaValidator->validateReport($report, $schema); + $this->repository->store($report); + } +} diff --git a/openapi-administration.json b/openapi-administration.json new file mode 100644 index 0000000..812b6f5 --- /dev/null +++ b/openapi-administration.json @@ -0,0 +1,1544 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "usage_statistics_server-administration", + "version": "0.0.1", + "description": "Receive and aggregate privacy-preserving usage statistics.", + "license": { + "name": "agpl" + } + }, + "components": { + "securitySchemes": { + "basic_auth": { + "type": "http", + "scheme": "basic" + }, + "bearer_auth": { + "type": "http", + "scheme": "bearer" + } + }, + "schemas": { + "OCSMeta": { + "type": "object", + "required": [ + "status", + "statuscode" + ], + "properties": { + "status": { + "type": "string" + }, + "statuscode": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "totalitems": { + "type": "string" + }, + "itemsperpage": { + "type": "string" + } + } + } + } + }, + "paths": { + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/schemas": { + "post": { + "operationId": "schema-create", + "summary": "Register an application metric schema", + "description": "This endpoint requires admin access", + "tags": [ + "schema" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "application", + "schemaVersion", + "metrics" + ], + "properties": { + "application": { + "type": "string", + "description": "Stable application identifier" + }, + "schemaVersion": { + "type": "integer", + "format": "int64", + "description": "Immutable schema version" + }, + "metrics": { + "type": "array", + "description": "Metric definitions", + "items": { + "type": "object", + "required": [ + "category", + "key", + "type", + "kind", + "aggregation", + "description", + "required" + ], + "properties": { + "category": { + "type": "string" + }, + "key": { + "type": "string" + }, + "type": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "aggregation": { + "type": "string" + }, + "description": { + "type": "string" + }, + "required": { + "type": "boolean" + } + } + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Schema was already registered with the same definition", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "application", + "schemaVersion", + "status" + ], + "properties": { + "application": { + "type": "string" + }, + "schemaVersion": { + "type": "integer", + "format": "int64" + }, + "status": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "201": { + "description": "Schema registered", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "application", + "schemaVersion", + "status" + ], + "properties": { + "application": { + "type": "string" + }, + "schemaVersion": { + "type": "integer", + "format": "int64" + }, + "status": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Invalid schema definition", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "409": { + "description": "Schema version already exists with another definition", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/schemas/{application}/{schemaVersion}": { + "get": { + "operationId": "schema-get", + "summary": "Get one registered application metric schema", + "description": "This endpoint requires admin access", + "tags": [ + "schema" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "application", + "in": "path", + "description": "Stable application identifier", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "schemaVersion", + "in": "path", + "description": "Schema version", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Registered schema definition", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "404": { + "description": "Schema not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/settings": { + "get": { + "operationId": "settings-get", + "summary": "Get usage statistics server settings", + "description": "This endpoint requires admin access", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Current server settings", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "retentionDays", + "minimumRetentionDays", + "maximumRetentionDays" + ], + "properties": { + "retentionDays": { + "type": "integer", + "format": "int64" + }, + "minimumRetentionDays": { + "type": "integer", + "format": "int64" + }, + "maximumRetentionDays": { + "type": "integer", + "format": "int64" + } + } + } + } + } + } + } + } + } + } + } + }, + "put": { + "operationId": "settings-update", + "summary": "Update usage statistics server settings", + "description": "This endpoint requires admin access", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "retentionDays" + ], + "properties": { + "retentionDays": { + "type": "integer", + "format": "int64", + "description": "Number of days to retain reports" + } + } + } + } + } + }, + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Server settings updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "retentionDays" + ], + "properties": { + "retentionDays": { + "type": "integer", + "format": "int64" + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Invalid retention value", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/applications/{application}": { + "get": { + "operationId": "statistics-summary", + "summary": "Get application usage statistics summary", + "description": "This endpoint requires admin access", + "tags": [ + "statistics" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "application", + "in": "path", + "description": "Stable application identifier", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Application usage statistics summary", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "application", + "activeWindowDays", + "activeInstallations" + ], + "properties": { + "application": { + "type": "string" + }, + "activeWindowDays": { + "type": "integer", + "format": "int64" + }, + "activeInstallations": { + "type": "integer", + "format": "int64" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/applications/{application}/metrics/{category}/{key}/distribution": { + "get": { + "operationId": "statistics-distribution", + "summary": "Get the current distribution for a metric", + "description": "This endpoint requires admin access", + "tags": [ + "statistics" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "application", + "in": "path", + "description": "Stable application identifier", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "category", + "in": "path", + "description": "Metric category", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "key", + "in": "path", + "description": "Metric key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Current metric distribution", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "application", + "category", + "key", + "values" + ], + "properties": { + "application": { + "type": "string" + }, + "category": { + "type": "string" + }, + "key": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "type": "object", + "required": [ + "value", + "count" + ], + "properties": { + "value": { + "type": "object" + }, + "count": { + "type": "integer", + "format": "int64" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Metric does not support distribution aggregation", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "404": { + "description": "Metric is not registered", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/applications/{application}/metrics/{category}/{key}/numerical": { + "get": { + "operationId": "statistics-numerical", + "summary": "Get the current numerical evaluation for a metric", + "description": "This endpoint requires admin access", + "tags": [ + "statistics" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "application", + "in": "path", + "description": "Stable application identifier", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "category", + "in": "path", + "description": "Metric category", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "key", + "in": "path", + "description": "Metric key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Current numerical metric evaluation", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "application", + "category", + "key", + "statistics" + ], + "properties": { + "application": { + "type": "string" + }, + "category": { + "type": "string" + }, + "key": { + "type": "string" + }, + "statistics": { + "type": "object", + "required": [ + "count", + "average", + "min", + "max", + "total" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64" + }, + "average": { + "type": "number", + "format": "double", + "nullable": true + }, + "min": { + "type": "number", + "format": "double", + "nullable": true + }, + "max": { + "type": "number", + "format": "double", + "nullable": true + }, + "total": { + "type": "number", + "format": "double", + "nullable": true + } + } + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Metric does not support numerical aggregation", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "404": { + "description": "Metric is not registered", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/applications/{application}/metrics/{category}/{key}/numerical/history": { + "get": { + "operationId": "statistics-numerical-history", + "summary": "Get historical numerical evaluation for a metric", + "description": "This endpoint requires admin access", + "tags": [ + "statistics" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "application", + "in": "path", + "description": "Stable application identifier", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "category", + "in": "path", + "description": "Metric category", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "key", + "in": "path", + "description": "Metric key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "from", + "in": "query", + "description": "Optional RFC3339 lower bound", + "schema": { + "type": "string", + "default": "" + } + }, + { + "name": "to", + "in": "query", + "description": "Optional RFC3339 upper bound", + "schema": { + "type": "string", + "default": "" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Historical numerical metric evaluation", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "application", + "category", + "key", + "from", + "to", + "periods" + ], + "properties": { + "application": { + "type": "string" + }, + "category": { + "type": "string" + }, + "key": { + "type": "string" + }, + "from": { + "type": "string" + }, + "to": { + "type": "string" + }, + "periods": { + "type": "array", + "items": { + "type": "object", + "required": [ + "periodStart", + "periodEnd", + "count", + "average", + "min", + "max", + "total" + ], + "properties": { + "periodStart": { + "type": "string" + }, + "periodEnd": { + "type": "string" + }, + "count": { + "type": "integer", + "format": "int64" + }, + "average": { + "type": "number", + "format": "double", + "nullable": true + }, + "min": { + "type": "number", + "format": "double", + "nullable": true + }, + "max": { + "type": "number", + "format": "double", + "nullable": true + }, + "total": { + "type": "number", + "format": "double", + "nullable": true + } + } + } + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Invalid date range or metric aggregation", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "404": { + "description": "Metric is not registered", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "tags": [] +} diff --git a/openapi-full.json b/openapi-full.json new file mode 100644 index 0000000..2000aa4 --- /dev/null +++ b/openapi-full.json @@ -0,0 +1,2000 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "usage_statistics_server-full", + "version": "0.0.1", + "description": "Receive and aggregate privacy-preserving usage statistics.", + "license": { + "name": "agpl" + } + }, + "components": { + "securitySchemes": { + "basic_auth": { + "type": "http", + "scheme": "basic" + }, + "bearer_auth": { + "type": "http", + "scheme": "bearer" + } + }, + "schemas": { + "OCSMeta": { + "type": "object", + "required": [ + "status", + "statuscode" + ], + "properties": { + "status": { + "type": "string" + }, + "statuscode": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "totalitems": { + "type": "string" + }, + "itemsperpage": { + "type": "string" + } + } + } + } + }, + "paths": { + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/reports": { + "post": { + "operationId": "ocs_report-create", + "summary": "Submit a usage statistics report through the Nextcloud OCS API", + "description": "This endpoint has the same Protocol v1 request semantics as the plain JSON endpoint, but wraps the response using the standard Nextcloud OCS envelope.", + "tags": [ + "ocs_report" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "protocolVersion", + "application", + "installationId", + "schemaVersion", + "period", + "metrics" + ], + "properties": { + "protocolVersion": { + "type": "integer", + "format": "int64", + "description": "Usage statistics protocol version" + }, + "application": { + "type": "string", + "description": "Stable application identifier" + }, + "installationId": { + "type": "string", + "description": "Stable pseudonymous installation identifier" + }, + "schemaVersion": { + "type": "integer", + "format": "int64", + "description": "Registered application schema version" + }, + "period": { + "type": "object", + "description": "RFC3339 reporting period, start inclusive and end exclusive", + "required": [ + "start", + "end" + ], + "properties": { + "start": { + "type": "string" + }, + "end": { + "type": "string" + } + } + }, + "metrics": { + "type": "array", + "description": "Aggregate metric values", + "items": { + "type": "object", + "required": [ + "category", + "key", + "type", + "value" + ], + "properties": { + "category": { + "type": "string" + }, + "key": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer", + "format": "int64" + }, + { + "type": "number", + "format": "double" + }, + { + "type": "boolean" + } + ] + } + } + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Report accepted", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "status" + ], + "properties": { + "status": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Invalid report", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "409": { + "description": "Conflicting report for the reporting period", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/index.php/apps/usage_statistics_server/api/{apiVersion}/reports": { + "post": { + "operationId": "report-create", + "summary": "Submit a usage statistics report as plain Protocol v1 JSON", + "description": "Stores one validated report for one application installation and reporting period. Repeating an already accepted report with the same schema version is idempotent.", + "tags": [ + "report" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "protocolVersion", + "application", + "installationId", + "schemaVersion", + "period", + "metrics" + ], + "properties": { + "protocolVersion": { + "type": "integer", + "format": "int64", + "description": "Usage statistics protocol version" + }, + "application": { + "type": "string", + "description": "Stable application identifier" + }, + "installationId": { + "type": "string", + "description": "Stable pseudonymous installation identifier" + }, + "schemaVersion": { + "type": "integer", + "format": "int64", + "description": "Registered application schema version" + }, + "period": { + "type": "object", + "description": "RFC3339 reporting period, start inclusive and end exclusive", + "required": [ + "start", + "end" + ], + "properties": { + "start": { + "type": "string" + }, + "end": { + "type": "string" + } + } + }, + "metrics": { + "type": "array", + "description": "Aggregate metric values", + "items": { + "type": "object", + "required": [ + "category", + "key", + "type", + "value" + ], + "properties": { + "category": { + "type": "string" + }, + "key": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer", + "format": "int64" + }, + { + "type": "number", + "format": "double" + }, + { + "type": "boolean" + } + ] + } + } + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + } + ], + "responses": { + "200": { + "description": "Report accepted", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "status" + ], + "properties": { + "status": { + "type": "string" + } + } + } + } + } + }, + "400": { + "description": "Invalid report", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "409": { + "description": "Conflicting report for the reporting period", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/schemas": { + "post": { + "operationId": "schema-create", + "summary": "Register an application metric schema", + "description": "This endpoint requires admin access", + "tags": [ + "schema" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "application", + "schemaVersion", + "metrics" + ], + "properties": { + "application": { + "type": "string", + "description": "Stable application identifier" + }, + "schemaVersion": { + "type": "integer", + "format": "int64", + "description": "Immutable schema version" + }, + "metrics": { + "type": "array", + "description": "Metric definitions", + "items": { + "type": "object", + "required": [ + "category", + "key", + "type", + "kind", + "aggregation", + "description", + "required" + ], + "properties": { + "category": { + "type": "string" + }, + "key": { + "type": "string" + }, + "type": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "aggregation": { + "type": "string" + }, + "description": { + "type": "string" + }, + "required": { + "type": "boolean" + } + } + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Schema was already registered with the same definition", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "application", + "schemaVersion", + "status" + ], + "properties": { + "application": { + "type": "string" + }, + "schemaVersion": { + "type": "integer", + "format": "int64" + }, + "status": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "201": { + "description": "Schema registered", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "application", + "schemaVersion", + "status" + ], + "properties": { + "application": { + "type": "string" + }, + "schemaVersion": { + "type": "integer", + "format": "int64" + }, + "status": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Invalid schema definition", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "409": { + "description": "Schema version already exists with another definition", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/schemas/{application}/{schemaVersion}": { + "get": { + "operationId": "schema-get", + "summary": "Get one registered application metric schema", + "description": "This endpoint requires admin access", + "tags": [ + "schema" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "application", + "in": "path", + "description": "Stable application identifier", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "schemaVersion", + "in": "path", + "description": "Schema version", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Registered schema definition", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "404": { + "description": "Schema not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/settings": { + "get": { + "operationId": "settings-get", + "summary": "Get usage statistics server settings", + "description": "This endpoint requires admin access", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Current server settings", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "retentionDays", + "minimumRetentionDays", + "maximumRetentionDays" + ], + "properties": { + "retentionDays": { + "type": "integer", + "format": "int64" + }, + "minimumRetentionDays": { + "type": "integer", + "format": "int64" + }, + "maximumRetentionDays": { + "type": "integer", + "format": "int64" + } + } + } + } + } + } + } + } + } + } + } + }, + "put": { + "operationId": "settings-update", + "summary": "Update usage statistics server settings", + "description": "This endpoint requires admin access", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "retentionDays" + ], + "properties": { + "retentionDays": { + "type": "integer", + "format": "int64", + "description": "Number of days to retain reports" + } + } + } + } + } + }, + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Server settings updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "retentionDays" + ], + "properties": { + "retentionDays": { + "type": "integer", + "format": "int64" + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Invalid retention value", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/applications/{application}": { + "get": { + "operationId": "statistics-summary", + "summary": "Get application usage statistics summary", + "description": "This endpoint requires admin access", + "tags": [ + "statistics" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "application", + "in": "path", + "description": "Stable application identifier", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Application usage statistics summary", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "application", + "activeWindowDays", + "activeInstallations" + ], + "properties": { + "application": { + "type": "string" + }, + "activeWindowDays": { + "type": "integer", + "format": "int64" + }, + "activeInstallations": { + "type": "integer", + "format": "int64" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/applications/{application}/metrics/{category}/{key}/distribution": { + "get": { + "operationId": "statistics-distribution", + "summary": "Get the current distribution for a metric", + "description": "This endpoint requires admin access", + "tags": [ + "statistics" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "application", + "in": "path", + "description": "Stable application identifier", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "category", + "in": "path", + "description": "Metric category", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "key", + "in": "path", + "description": "Metric key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Current metric distribution", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "application", + "category", + "key", + "values" + ], + "properties": { + "application": { + "type": "string" + }, + "category": { + "type": "string" + }, + "key": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "type": "object", + "required": [ + "value", + "count" + ], + "properties": { + "value": { + "type": "object" + }, + "count": { + "type": "integer", + "format": "int64" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Metric does not support distribution aggregation", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "404": { + "description": "Metric is not registered", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/applications/{application}/metrics/{category}/{key}/numerical": { + "get": { + "operationId": "statistics-numerical", + "summary": "Get the current numerical evaluation for a metric", + "description": "This endpoint requires admin access", + "tags": [ + "statistics" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "application", + "in": "path", + "description": "Stable application identifier", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "category", + "in": "path", + "description": "Metric category", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "key", + "in": "path", + "description": "Metric key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Current numerical metric evaluation", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "application", + "category", + "key", + "statistics" + ], + "properties": { + "application": { + "type": "string" + }, + "category": { + "type": "string" + }, + "key": { + "type": "string" + }, + "statistics": { + "type": "object", + "required": [ + "count", + "average", + "min", + "max", + "total" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64" + }, + "average": { + "type": "number", + "format": "double", + "nullable": true + }, + "min": { + "type": "number", + "format": "double", + "nullable": true + }, + "max": { + "type": "number", + "format": "double", + "nullable": true + }, + "total": { + "type": "number", + "format": "double", + "nullable": true + } + } + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Metric does not support numerical aggregation", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "404": { + "description": "Metric is not registered", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/applications/{application}/metrics/{category}/{key}/numerical/history": { + "get": { + "operationId": "statistics-numerical-history", + "summary": "Get historical numerical evaluation for a metric", + "description": "This endpoint requires admin access", + "tags": [ + "statistics" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "application", + "in": "path", + "description": "Stable application identifier", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "category", + "in": "path", + "description": "Metric category", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "key", + "in": "path", + "description": "Metric key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "from", + "in": "query", + "description": "Optional RFC3339 lower bound", + "schema": { + "type": "string", + "default": "" + } + }, + { + "name": "to", + "in": "query", + "description": "Optional RFC3339 upper bound", + "schema": { + "type": "string", + "default": "" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Historical numerical metric evaluation", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "application", + "category", + "key", + "from", + "to", + "periods" + ], + "properties": { + "application": { + "type": "string" + }, + "category": { + "type": "string" + }, + "key": { + "type": "string" + }, + "from": { + "type": "string" + }, + "to": { + "type": "string" + }, + "periods": { + "type": "array", + "items": { + "type": "object", + "required": [ + "periodStart", + "periodEnd", + "count", + "average", + "min", + "max", + "total" + ], + "properties": { + "periodStart": { + "type": "string" + }, + "periodEnd": { + "type": "string" + }, + "count": { + "type": "integer", + "format": "int64" + }, + "average": { + "type": "number", + "format": "double", + "nullable": true + }, + "min": { + "type": "number", + "format": "double", + "nullable": true + }, + "max": { + "type": "number", + "format": "double", + "nullable": true + }, + "total": { + "type": "number", + "format": "double", + "nullable": true + } + } + } + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Invalid date range or metric aggregation", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "404": { + "description": "Metric is not registered", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "tags": [] +} diff --git a/openapi.json b/openapi.json new file mode 100644 index 0000000..9010698 --- /dev/null +++ b/openapi.json @@ -0,0 +1,508 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "usage_statistics_server", + "version": "0.0.1", + "description": "Receive and aggregate privacy-preserving usage statistics.", + "license": { + "name": "agpl" + } + }, + "components": { + "securitySchemes": { + "basic_auth": { + "type": "http", + "scheme": "basic" + }, + "bearer_auth": { + "type": "http", + "scheme": "bearer" + } + }, + "schemas": { + "OCSMeta": { + "type": "object", + "required": [ + "status", + "statuscode" + ], + "properties": { + "status": { + "type": "string" + }, + "statuscode": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "totalitems": { + "type": "string" + }, + "itemsperpage": { + "type": "string" + } + } + } + } + }, + "paths": { + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/reports": { + "post": { + "operationId": "ocs_report-create", + "summary": "Submit a usage statistics report through the Nextcloud OCS API", + "description": "This endpoint has the same Protocol v1 request semantics as the plain JSON endpoint, but wraps the response using the standard Nextcloud OCS envelope.", + "tags": [ + "ocs_report" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "protocolVersion", + "application", + "installationId", + "schemaVersion", + "period", + "metrics" + ], + "properties": { + "protocolVersion": { + "type": "integer", + "format": "int64", + "description": "Usage statistics protocol version" + }, + "application": { + "type": "string", + "description": "Stable application identifier" + }, + "installationId": { + "type": "string", + "description": "Stable pseudonymous installation identifier" + }, + "schemaVersion": { + "type": "integer", + "format": "int64", + "description": "Registered application schema version" + }, + "period": { + "type": "object", + "description": "RFC3339 reporting period, start inclusive and end exclusive", + "required": [ + "start", + "end" + ], + "properties": { + "start": { + "type": "string" + }, + "end": { + "type": "string" + } + } + }, + "metrics": { + "type": "array", + "description": "Aggregate metric values", + "items": { + "type": "object", + "required": [ + "category", + "key", + "type", + "value" + ], + "properties": { + "category": { + "type": "string" + }, + "key": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer", + "format": "int64" + }, + { + "type": "number", + "format": "double" + }, + { + "type": "boolean" + } + ] + } + } + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Report accepted", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "status" + ], + "properties": { + "status": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Invalid report", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "409": { + "description": "Conflicting report for the reporting period", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/index.php/apps/usage_statistics_server/api/{apiVersion}/reports": { + "post": { + "operationId": "report-create", + "summary": "Submit a usage statistics report as plain Protocol v1 JSON", + "description": "Stores one validated report for one application installation and reporting period. Repeating an already accepted report with the same schema version is idempotent.", + "tags": [ + "report" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "protocolVersion", + "application", + "installationId", + "schemaVersion", + "period", + "metrics" + ], + "properties": { + "protocolVersion": { + "type": "integer", + "format": "int64", + "description": "Usage statistics protocol version" + }, + "application": { + "type": "string", + "description": "Stable application identifier" + }, + "installationId": { + "type": "string", + "description": "Stable pseudonymous installation identifier" + }, + "schemaVersion": { + "type": "integer", + "format": "int64", + "description": "Registered application schema version" + }, + "period": { + "type": "object", + "description": "RFC3339 reporting period, start inclusive and end exclusive", + "required": [ + "start", + "end" + ], + "properties": { + "start": { + "type": "string" + }, + "end": { + "type": "string" + } + } + }, + "metrics": { + "type": "array", + "description": "Aggregate metric values", + "items": { + "type": "object", + "required": [ + "category", + "key", + "type", + "value" + ], + "properties": { + "category": { + "type": "string" + }, + "key": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer", + "format": "int64" + }, + { + "type": "number", + "format": "double" + }, + { + "type": "boolean" + } + ] + } + } + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v1" + ], + "default": "v1" + } + } + ], + "responses": { + "200": { + "description": "Report accepted", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "status" + ], + "properties": { + "status": { + "type": "string" + } + } + } + } + } + }, + "400": { + "description": "Invalid report", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "409": { + "description": "Conflicting report for the reporting period", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "tags": [] +} diff --git a/src/types/openapi/openapi-administration.ts b/src/types/openapi/openapi-administration.ts new file mode 100644 index 0000000..1056f9a --- /dev/null +++ b/src/types/openapi/openapi-administration.ts @@ -0,0 +1,728 @@ +/** + * This file was auto-generated by openapi-typescript. + * Do not make direct changes to the file. + */ + +export type paths = { + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/schemas": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Register an application metric schema + * @description This endpoint requires admin access + */ + post: operations["schema-create"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/schemas/{application}/{schemaVersion}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get one registered application metric schema + * @description This endpoint requires admin access + */ + get: operations["schema-get"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/settings": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get usage statistics server settings + * @description This endpoint requires admin access + */ + get: operations["settings-get"]; + /** + * Update usage statistics server settings + * @description This endpoint requires admin access + */ + put: operations["settings-update"]; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/applications/{application}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get application usage statistics summary + * @description This endpoint requires admin access + */ + get: operations["statistics-summary"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/applications/{application}/metrics/{category}/{key}/distribution": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get the current distribution for a metric + * @description This endpoint requires admin access + */ + get: operations["statistics-distribution"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/applications/{application}/metrics/{category}/{key}/numerical": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get the current numerical evaluation for a metric + * @description This endpoint requires admin access + */ + get: operations["statistics-numerical"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/applications/{application}/metrics/{category}/{key}/numerical/history": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get historical numerical evaluation for a metric + * @description This endpoint requires admin access + */ + get: operations["statistics-numerical-history"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; +}; +export type webhooks = Record; +export type components = { + schemas: { + OCSMeta: { + status: string; + statuscode: number; + message?: string; + totalitems?: string; + itemsperpage?: string; + }; + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; +}; +export type $defs = Record; +export interface operations { + "schema-create": { + parameters: { + query?: never; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** @description Stable application identifier */ + application: string; + /** + * Format: int64 + * @description Immutable schema version + */ + schemaVersion: number; + /** @description Metric definitions */ + metrics: { + category: string; + key: string; + type: string; + kind: string; + aggregation: string; + description: string; + required: boolean; + }[]; + }; + }; + }; + responses: { + /** @description Schema was already registered with the same definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + application: string; + /** Format: int64 */ + schemaVersion: number; + status: string; + }; + }; + }; + }; + }; + /** @description Schema registered */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + application: string; + /** Format: int64 */ + schemaVersion: number; + status: string; + }; + }; + }; + }; + }; + /** @description Invalid schema definition */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + /** @description Schema version already exists with another definition */ + 409: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + }; + }; + "schema-get": { + parameters: { + query?: never; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + /** @description Stable application identifier */ + application: string; + /** @description Schema version */ + schemaVersion: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Registered schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + [key: string]: Record; + }; + }; + }; + }; + }; + /** @description Schema not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + }; + }; + }; + }; + }; + }; + }; + "settings-get": { + parameters: { + query?: never; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Current server settings */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + /** Format: int64 */ + retentionDays: number; + /** Format: int64 */ + minimumRetentionDays: number; + /** Format: int64 */ + maximumRetentionDays: number; + }; + }; + }; + }; + }; + }; + }; + "settings-update": { + parameters: { + query?: never; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** + * Format: int64 + * @description Number of days to retain reports + */ + retentionDays: number; + }; + }; + }; + responses: { + /** @description Server settings updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + /** Format: int64 */ + retentionDays: number; + }; + }; + }; + }; + }; + /** @description Invalid retention value */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + }; + }; + "statistics-summary": { + parameters: { + query?: never; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + /** @description Stable application identifier */ + application: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Application usage statistics summary */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + application: string; + /** Format: int64 */ + activeWindowDays: number; + /** Format: int64 */ + activeInstallations: number; + }; + }; + }; + }; + }; + }; + }; + "statistics-distribution": { + parameters: { + query?: never; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + /** @description Stable application identifier */ + application: string; + /** @description Metric category */ + category: string; + /** @description Metric key */ + key: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Current metric distribution */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + application: string; + category: string; + key: string; + values: { + value: Record; + /** Format: int64 */ + count: number; + }[]; + }; + }; + }; + }; + }; + /** @description Metric does not support distribution aggregation */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + /** @description Metric is not registered */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + }; + }; + "statistics-numerical": { + parameters: { + query?: never; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + /** @description Stable application identifier */ + application: string; + /** @description Metric category */ + category: string; + /** @description Metric key */ + key: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Current numerical metric evaluation */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + application: string; + category: string; + key: string; + statistics: { + /** Format: int64 */ + count: number; + /** Format: double */ + average: number | null; + /** Format: double */ + min: number | null; + /** Format: double */ + max: number | null; + /** Format: double */ + total: number | null; + }; + }; + }; + }; + }; + }; + /** @description Metric does not support numerical aggregation */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + /** @description Metric is not registered */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + }; + }; + "statistics-numerical-history": { + parameters: { + query?: { + /** @description Optional RFC3339 lower bound */ + from?: string; + /** @description Optional RFC3339 upper bound */ + to?: string; + }; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + /** @description Stable application identifier */ + application: string; + /** @description Metric category */ + category: string; + /** @description Metric key */ + key: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Historical numerical metric evaluation */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + application: string; + category: string; + key: string; + from: string; + to: string; + periods: { + periodStart: string; + periodEnd: string; + /** Format: int64 */ + count: number; + /** Format: double */ + average: number | null; + /** Format: double */ + min: number | null; + /** Format: double */ + max: number | null; + /** Format: double */ + total: number | null; + }[]; + }; + }; + }; + }; + }; + /** @description Invalid date range or metric aggregation */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + /** @description Metric is not registered */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/src/types/openapi/openapi-full.ts b/src/types/openapi/openapi-full.ts new file mode 100644 index 0000000..0b4cb16 --- /dev/null +++ b/src/types/openapi/openapi-full.ts @@ -0,0 +1,944 @@ +/** + * This file was auto-generated by openapi-typescript. + * Do not make direct changes to the file. + */ + +export type paths = { + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/reports": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Submit a usage statistics report through the Nextcloud OCS API + * @description This endpoint has the same Protocol v1 request semantics as the plain JSON endpoint, but wraps the response using the standard Nextcloud OCS envelope. + */ + post: operations["ocs_report-create"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/index.php/apps/usage_statistics_server/api/{apiVersion}/reports": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Submit a usage statistics report as plain Protocol v1 JSON + * @description Stores one validated report for one application installation and reporting period. Repeating an already accepted report with the same schema version is idempotent. + */ + post: operations["report-create"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/schemas": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Register an application metric schema + * @description This endpoint requires admin access + */ + post: operations["schema-create"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/schemas/{application}/{schemaVersion}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get one registered application metric schema + * @description This endpoint requires admin access + */ + get: operations["schema-get"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/settings": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get usage statistics server settings + * @description This endpoint requires admin access + */ + get: operations["settings-get"]; + /** + * Update usage statistics server settings + * @description This endpoint requires admin access + */ + put: operations["settings-update"]; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/applications/{application}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get application usage statistics summary + * @description This endpoint requires admin access + */ + get: operations["statistics-summary"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/applications/{application}/metrics/{category}/{key}/distribution": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get the current distribution for a metric + * @description This endpoint requires admin access + */ + get: operations["statistics-distribution"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/applications/{application}/metrics/{category}/{key}/numerical": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get the current numerical evaluation for a metric + * @description This endpoint requires admin access + */ + get: operations["statistics-numerical"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/admin/applications/{application}/metrics/{category}/{key}/numerical/history": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get historical numerical evaluation for a metric + * @description This endpoint requires admin access + */ + get: operations["statistics-numerical-history"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; +}; +export type webhooks = Record; +export type components = { + schemas: { + OCSMeta: { + status: string; + statuscode: number; + message?: string; + totalitems?: string; + itemsperpage?: string; + }; + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; +}; +export type $defs = Record; +export interface operations { + "ocs_report-create": { + parameters: { + query?: never; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** + * Format: int64 + * @description Usage statistics protocol version + */ + protocolVersion: number; + /** @description Stable application identifier */ + application: string; + /** @description Stable pseudonymous installation identifier */ + installationId: string; + /** + * Format: int64 + * @description Registered application schema version + */ + schemaVersion: number; + /** @description RFC3339 reporting period, start inclusive and end exclusive */ + period: { + start: string; + end: string; + }; + /** @description Aggregate metric values */ + metrics: { + category: string; + key: string; + type: string; + value: string | number | boolean; + }[]; + }; + }; + }; + responses: { + /** @description Report accepted */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + status: string; + }; + }; + }; + }; + }; + /** @description Invalid report */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + /** @description Conflicting report for the reporting period */ + 409: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + }; + }; + "report-create": { + parameters: { + query?: never; + header?: never; + path: { + apiVersion: "v1"; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** + * Format: int64 + * @description Usage statistics protocol version + */ + protocolVersion: number; + /** @description Stable application identifier */ + application: string; + /** @description Stable pseudonymous installation identifier */ + installationId: string; + /** + * Format: int64 + * @description Registered application schema version + */ + schemaVersion: number; + /** @description RFC3339 reporting period, start inclusive and end exclusive */ + period: { + start: string; + end: string; + }; + /** @description Aggregate metric values */ + metrics: { + category: string; + key: string; + type: string; + value: string | number | boolean; + }[]; + }; + }; + }; + responses: { + /** @description Report accepted */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + status: string; + }; + }; + }; + /** @description Invalid report */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error: string; + message: string; + }; + }; + }; + /** @description Conflicting report for the reporting period */ + 409: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error: string; + message: string; + }; + }; + }; + }; + }; + "schema-create": { + parameters: { + query?: never; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** @description Stable application identifier */ + application: string; + /** + * Format: int64 + * @description Immutable schema version + */ + schemaVersion: number; + /** @description Metric definitions */ + metrics: { + category: string; + key: string; + type: string; + kind: string; + aggregation: string; + description: string; + required: boolean; + }[]; + }; + }; + }; + responses: { + /** @description Schema was already registered with the same definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + application: string; + /** Format: int64 */ + schemaVersion: number; + status: string; + }; + }; + }; + }; + }; + /** @description Schema registered */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + application: string; + /** Format: int64 */ + schemaVersion: number; + status: string; + }; + }; + }; + }; + }; + /** @description Invalid schema definition */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + /** @description Schema version already exists with another definition */ + 409: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + }; + }; + "schema-get": { + parameters: { + query?: never; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + /** @description Stable application identifier */ + application: string; + /** @description Schema version */ + schemaVersion: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Registered schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + [key: string]: Record; + }; + }; + }; + }; + }; + /** @description Schema not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + }; + }; + }; + }; + }; + }; + }; + "settings-get": { + parameters: { + query?: never; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Current server settings */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + /** Format: int64 */ + retentionDays: number; + /** Format: int64 */ + minimumRetentionDays: number; + /** Format: int64 */ + maximumRetentionDays: number; + }; + }; + }; + }; + }; + }; + }; + "settings-update": { + parameters: { + query?: never; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** + * Format: int64 + * @description Number of days to retain reports + */ + retentionDays: number; + }; + }; + }; + responses: { + /** @description Server settings updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + /** Format: int64 */ + retentionDays: number; + }; + }; + }; + }; + }; + /** @description Invalid retention value */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + }; + }; + "statistics-summary": { + parameters: { + query?: never; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + /** @description Stable application identifier */ + application: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Application usage statistics summary */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + application: string; + /** Format: int64 */ + activeWindowDays: number; + /** Format: int64 */ + activeInstallations: number; + }; + }; + }; + }; + }; + }; + }; + "statistics-distribution": { + parameters: { + query?: never; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + /** @description Stable application identifier */ + application: string; + /** @description Metric category */ + category: string; + /** @description Metric key */ + key: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Current metric distribution */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + application: string; + category: string; + key: string; + values: { + value: Record; + /** Format: int64 */ + count: number; + }[]; + }; + }; + }; + }; + }; + /** @description Metric does not support distribution aggregation */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + /** @description Metric is not registered */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + }; + }; + "statistics-numerical": { + parameters: { + query?: never; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + /** @description Stable application identifier */ + application: string; + /** @description Metric category */ + category: string; + /** @description Metric key */ + key: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Current numerical metric evaluation */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + application: string; + category: string; + key: string; + statistics: { + /** Format: int64 */ + count: number; + /** Format: double */ + average: number | null; + /** Format: double */ + min: number | null; + /** Format: double */ + max: number | null; + /** Format: double */ + total: number | null; + }; + }; + }; + }; + }; + }; + /** @description Metric does not support numerical aggregation */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + /** @description Metric is not registered */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + }; + }; + "statistics-numerical-history": { + parameters: { + query?: { + /** @description Optional RFC3339 lower bound */ + from?: string; + /** @description Optional RFC3339 upper bound */ + to?: string; + }; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + /** @description Stable application identifier */ + application: string; + /** @description Metric category */ + category: string; + /** @description Metric key */ + key: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Historical numerical metric evaluation */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + application: string; + category: string; + key: string; + from: string; + to: string; + periods: { + periodStart: string; + periodEnd: string; + /** Format: int64 */ + count: number; + /** Format: double */ + average: number | null; + /** Format: double */ + min: number | null; + /** Format: double */ + max: number | null; + /** Format: double */ + total: number | null; + }[]; + }; + }; + }; + }; + }; + /** @description Invalid date range or metric aggregation */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + /** @description Metric is not registered */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/src/types/openapi/openapi.ts b/src/types/openapi/openapi.ts new file mode 100644 index 0000000..fe2419a --- /dev/null +++ b/src/types/openapi/openapi.ts @@ -0,0 +1,243 @@ +/** + * This file was auto-generated by openapi-typescript. + * Do not make direct changes to the file. + */ + +export type paths = { + "/ocs/v2.php/apps/usage_statistics_server/api/{apiVersion}/reports": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Submit a usage statistics report through the Nextcloud OCS API + * @description This endpoint has the same Protocol v1 request semantics as the plain JSON endpoint, but wraps the response using the standard Nextcloud OCS envelope. + */ + post: operations["ocs_report-create"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/index.php/apps/usage_statistics_server/api/{apiVersion}/reports": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Submit a usage statistics report as plain Protocol v1 JSON + * @description Stores one validated report for one application installation and reporting period. Repeating an already accepted report with the same schema version is idempotent. + */ + post: operations["report-create"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; +}; +export type webhooks = Record; +export type components = { + schemas: { + OCSMeta: { + status: string; + statuscode: number; + message?: string; + totalitems?: string; + itemsperpage?: string; + }; + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; +}; +export type $defs = Record; +export interface operations { + "ocs_report-create": { + parameters: { + query?: never; + header: { + /** @description Required to be true for the API request to pass */ + "OCS-APIRequest": boolean; + }; + path: { + apiVersion: "v1"; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** + * Format: int64 + * @description Usage statistics protocol version + */ + protocolVersion: number; + /** @description Stable application identifier */ + application: string; + /** @description Stable pseudonymous installation identifier */ + installationId: string; + /** + * Format: int64 + * @description Registered application schema version + */ + schemaVersion: number; + /** @description RFC3339 reporting period, start inclusive and end exclusive */ + period: { + start: string; + end: string; + }; + /** @description Aggregate metric values */ + metrics: { + category: string; + key: string; + type: string; + value: string | number | boolean; + }[]; + }; + }; + }; + responses: { + /** @description Report accepted */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + status: string; + }; + }; + }; + }; + }; + /** @description Invalid report */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + /** @description Conflicting report for the reporting period */ + 409: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ocs: { + meta: components["schemas"]["OCSMeta"]; + data: { + error: string; + message: string; + }; + }; + }; + }; + }; + }; + }; + "report-create": { + parameters: { + query?: never; + header?: never; + path: { + apiVersion: "v1"; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** + * Format: int64 + * @description Usage statistics protocol version + */ + protocolVersion: number; + /** @description Stable application identifier */ + application: string; + /** @description Stable pseudonymous installation identifier */ + installationId: string; + /** + * Format: int64 + * @description Registered application schema version + */ + schemaVersion: number; + /** @description RFC3339 reporting period, start inclusive and end exclusive */ + period: { + start: string; + end: string; + }; + /** @description Aggregate metric values */ + metrics: { + category: string; + key: string; + type: string; + value: string | number | boolean; + }[]; + }; + }; + }; + responses: { + /** @description Report accepted */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + status: string; + }; + }; + }; + /** @description Invalid report */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error: string; + message: string; + }; + }; + }; + /** @description Conflicting report for the reporting period */ + 409: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error: string; + message: string; + }; + }; + }; + }; + }; +} diff --git a/tests/integration/features/api/usage_statistics.feature b/tests/integration/features/api/usage_statistics.feature index 3594e27..606da96 100644 --- a/tests/integration/features/api/usage_statistics.feature +++ b/tests/integration/features/api/usage_statistics.feature @@ -59,7 +59,7 @@ Feature: usage statistics OCS API | metrics | [{"category":"server","key":"version","type":"string","kind":"snapshot","aggregation":"distribution","description":"Application version","required":true},{"category":"usage","key":"requests_completed","type":"integer","kind":"period","aggregation":"numerical","description":"Completed requests","required":true}] | Then the response should have a status code 201 Given as anonymous user - When sending "post" to ocs "/apps/usage_statistics_server/api/v1/reports" + When sending "post" to "/apps/usage_statistics_server/api/v1/reports" | protocolVersion | 1 | | application | behat_report | | installationId | install-behat-report | @@ -69,8 +69,8 @@ Feature: usage statistics OCS API Then the response should have a status code 200 And the response should be a JSON array with the following mandatory values | key | value | - | (jq).ocs.data.status | accepted | - When sending "post" to ocs "/apps/usage_statistics_server/api/v1/reports" + | (jq).status | accepted | + When sending "post" to "/apps/usage_statistics_server/api/v1/reports" | protocolVersion | 1 | | application | behat_report | | installationId | install-behat-report | @@ -78,6 +78,27 @@ Feature: usage statistics OCS API | period | {"start":"2026-08-01T00:00:00Z","end":"2026-09-01T00:00:00Z"} | | metrics | [{"category":"server","key":"version","type":"string","value":"1.0.0"},{"category":"usage","key":"requests_completed","type":"integer","value":12}] | Then the response should have a status code 200 + And the response should be a JSON array with the following mandatory values + | key | value | + | (jq).status | accepted | + + + Scenario: anonymous report submission is also available through OCS + Given as user "admin" + When sending "post" to ocs "/apps/usage_statistics_server/api/v1/admin/schemas" + | application | behat_report_ocs | + | schemaVersion | 1 | + | metrics | [{"category":"server","key":"version","type":"string","kind":"snapshot","aggregation":"distribution","description":"Application version","required":true}] | + Then the response should have a status code 201 + Given as anonymous user + When sending "post" to ocs "/apps/usage_statistics_server/api/v1/reports" + | protocolVersion | 1 | + | application | behat_report_ocs | + | installationId | install-behat-report-ocs | + | schemaVersion | 1 | + | period | {"start":"2026-08-01T00:00:00Z","end":"2026-09-01T00:00:00Z"} | + | metrics | [{"category":"server","key":"version","type":"string","value":"1.0.0"}] | + Then the response should have a status code 200 And the response should be a JSON array with the following mandatory values | key | value | | (jq).ocs.data.status | accepted | @@ -90,7 +111,7 @@ Feature: usage statistics OCS API | metrics | [{"category":"server","key":"version","type":"string","kind":"snapshot","aggregation":"distribution","description":"Application version","required":true}] | Then the response should have a status code 201 Given as anonymous user - When sending "post" to ocs "/apps/usage_statistics_server/api/v1/reports" + When sending "post" to "/apps/usage_statistics_server/api/v1/reports" | protocolVersion | 1 | | application | behat_unknown_metric | | installationId | install-unknown-metric | @@ -100,7 +121,7 @@ Feature: usage statistics OCS API Then the response should have a status code 400 And the response should be a JSON array with the following mandatory values | key | value | - | (jq).ocs.data.error | invalid_report | + | (jq).error | invalid_report | Scenario: changing schema version for the same installation and reporting period conflicts Given as user "admin" @@ -115,7 +136,7 @@ Feature: usage statistics OCS API | metrics | [{"category":"server","key":"version","type":"string","kind":"snapshot","aggregation":"distribution","description":"Application version","required":true}] | Then the response should have a status code 201 Given as anonymous user - When sending "post" to ocs "/apps/usage_statistics_server/api/v1/reports" + When sending "post" to "/apps/usage_statistics_server/api/v1/reports" | protocolVersion | 1 | | application | behat_period_conflict | | installationId | install-period-conflict | @@ -123,7 +144,7 @@ Feature: usage statistics OCS API | period | {"start":"2026-08-01T00:00:00Z","end":"2026-09-01T00:00:00Z"} | | metrics | [{"category":"server","key":"version","type":"string","value":"1.0.0"}] | Then the response should have a status code 200 - When sending "post" to ocs "/apps/usage_statistics_server/api/v1/reports" + When sending "post" to "/apps/usage_statistics_server/api/v1/reports" | protocolVersion | 1 | | application | behat_period_conflict | | installationId | install-period-conflict | @@ -133,7 +154,7 @@ Feature: usage statistics OCS API Then the response should have a status code 409 And the response should be a JSON array with the following mandatory values | key | value | - | (jq).ocs.data.error | conflicting_report | + | (jq).error | conflicting_report | Scenario: administrator can read current aggregates Given as user "admin" @@ -143,7 +164,7 @@ Feature: usage statistics OCS API | metrics | [{"category":"server","key":"version","type":"string","kind":"snapshot","aggregation":"distribution","description":"Application version","required":true},{"category":"usage","key":"requests_completed","type":"integer","kind":"period","aggregation":"numerical","description":"Completed requests","required":true}] | Then the response should have a status code 201 Given as anonymous user - When sending "post" to ocs "/apps/usage_statistics_server/api/v1/reports" + When sending "post" to "/apps/usage_statistics_server/api/v1/reports" | protocolVersion | 1 | | application | behat_statistics | | installationId | install-behat-statistics | diff --git a/tests/php/Integration/Service/ReportSubmissionServiceTest.php b/tests/php/Integration/Service/ReportSubmissionServiceTest.php new file mode 100644 index 0000000..2d32b7b --- /dev/null +++ b/tests/php/Integration/Service/ReportSubmissionServiceTest.php @@ -0,0 +1,120 @@ +db = Server::get(IDBConnection::class); + $this->schemas = new SchemaRepository($this->db); + $this->submission = new ReportSubmissionService( + new ReportFactory(), + new ReportRepository($this->db), + $this->schemas, + new SchemaValidator(), + ); + $this->clearTables(); + } + + protected function tearDown(): void { + $this->clearTables(); + parent::tearDown(); + } + + public function testSubmitsReportAgainstRegisteredSchema(): void { + $definition = [ + 'application' => 'integration_app', + 'schemaVersion' => 1, + 'metrics' => [[ + 'category' => 'usage', + 'key' => 'requests_completed', + 'type' => 'integer', + 'kind' => 'period', + 'aggregation' => 'numerical', + 'description' => 'Completed requests', + 'required' => true, + ]], + ]; + $this->schemas->store('integration_app', 1, $definition); + + $this->submission->submit($this->payload()); + + self::assertSame(1, $this->countRows('usage_stats_reports')); + self::assertSame(1, $this->countRows('usage_stats_metrics')); + } + + public function testRejectsReportWhenSchemaIsNotRegistered(): void { + $this->expectException(InvalidReport::class); + $this->expectExceptionMessage('Application schema is not registered.'); + + $this->submission->submit($this->payload()); + } + + /** + * @return array{ + * protocolVersion:int, + * application:string, + * installationId:string, + * schemaVersion:int, + * period:array{start:string,end:string}, + * metrics:list + * } + */ + private function payload(): array { + return [ + 'protocolVersion' => 1, + 'application' => 'integration_app', + 'installationId' => 'integration-installation', + 'schemaVersion' => 1, + 'period' => [ + 'start' => '2026-08-01T00:00:00Z', + 'end' => '2026-09-01T00:00:00Z', + ], + 'metrics' => [[ + 'category' => 'usage', + 'key' => 'requests_completed', + 'type' => 'integer', + 'value' => 12, + ]], + ]; + } + + private function countRows(string $table): int { + $qb = $this->db->getQueryBuilder(); + return (int)$qb + ->select($qb->func()->count()) + ->from($table) + ->executeQuery() + ->fetchOne(); + } + + private function clearTables(): void { + $this->db->getQueryBuilder()->delete('usage_stats_metrics')->executeStatement(); + $this->db->getQueryBuilder()->delete('usage_stats_installations')->executeStatement(); + $this->db->getQueryBuilder()->delete('usage_stats_reports')->executeStatement(); + $this->db->getQueryBuilder()->delete('usage_stats_schemas')->executeStatement(); + } +} diff --git a/vendor-bin/phpstan/composer.json b/vendor-bin/phpstan/composer.json index 52f4ed4..7c6eacf 100644 --- a/vendor-bin/phpstan/composer.json +++ b/vendor-bin/phpstan/composer.json @@ -1,6 +1,6 @@ { "require-dev": { - "doctrine/dbal": "^3.10.4", + "doctrine/dbal": "^4.5.0", "phpstan/phpstan": "^2.1", "symfony/console": "^6.4 || ^7.0" }, diff --git a/vendor-bin/psalm/composer.json b/vendor-bin/psalm/composer.json index 9c813e6..08bb383 100644 --- a/vendor-bin/psalm/composer.json +++ b/vendor-bin/psalm/composer.json @@ -6,6 +6,6 @@ "sort-packages": true }, "require-dev": { - "vimeo/psalm": "6.16.1" + "vimeo/psalm": "6.19.0" } }