From 784016013c78dabc4d72e7384e8d24675ba9b70f Mon Sep 17 00:00:00 2001
From: Renovate Bot <bot@renovateapp.com>
Date: Tue, 9 Apr 2024 11:46:34 +0000
Subject: [PATCH] Update dependency eslint to v9

---
 .eslintignore                                 |   1 -
 eslint.config.js                              |  59 ++++
 integration/.eslintrc                         |   5 -
 integration/.mocharc.cjs                      |   6 +-
 .eslintrc.cjs => integration/eslint.config.js |  28 +-
 package.json                                  |  14 +-
 pnpm-lock.yaml                                | 260 ++++++++++++++++--
 spec/.eslintrc                                |   5 -
 spec/.mocharc.cjs                             |   8 +-
 spec/eslint.config.js                         |  28 ++
 spec/pwa_test.js                              |   1 +
 spec/util_test.js                             |   1 +
 12 files changed, 357 insertions(+), 59 deletions(-)
 delete mode 100644 .eslintignore
 create mode 100644 eslint.config.js
 delete mode 100644 integration/.eslintrc
 rename .eslintrc.cjs => integration/eslint.config.js (71%)
 delete mode 100644 spec/.eslintrc
 create mode 100644 spec/eslint.config.js

diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index c2658d7..0000000
--- a/.eslintignore
+++ /dev/null
@@ -1 +0,0 @@
-node_modules/
diff --git a/eslint.config.js b/eslint.config.js
new file mode 100644
index 0000000..3ceca14
--- /dev/null
+++ b/eslint.config.js
@@ -0,0 +1,59 @@
+/**
+ * @copyright Copyright (c) Open-Xchange GmbH, Germany <info@open-xchange.com>
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with OX App Suite. If not, see <https://www.gnu.org/licenses/agpl-3.0.txt>.
+ *
+ * Any use of the work other than as authorized under this license or copyright law is prohibited.
+ */
+
+import { FlatCompat } from '@eslint/eslintrc'
+import { fileURLToPath } from 'url'
+import path from 'path'
+
+import licenseHeader from 'eslint-plugin-license-header'
+import specConfig from './spec/eslint.config.js'
+import integrationConfig from './integration/eslint.config.js'
+
+const __filename = fileURLToPath(import.meta.url)
+const __dirname = path.dirname(__filename)
+
+const flatCompat = new FlatCompat({
+  baseDirectory: __dirname
+})
+
+export default [
+  ...flatCompat.extends('eslint-config-standard'),
+  ...flatCompat.extends('plugin:chai-friendly/recommended'),
+  ...specConfig,
+  ...integrationConfig,
+  {
+    languageOptions: {
+      globals: {
+        browser: true,
+        es2022: true
+      }
+    },
+    plugins: {
+      licenseHeader
+    },
+    ignores: [
+      'public/*',
+      'node_modules/*'
+    ],
+    rules: {
+      'licenseHeader/header': ['error', path.join(__dirname, 'license-header')]
+    }
+  }
+]
diff --git a/integration/.eslintrc b/integration/.eslintrc
deleted file mode 100644
index 7eeefc3..0000000
--- a/integration/.eslintrc
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "env": {
-    "mocha": true
-  }
-}
diff --git a/integration/.mocharc.cjs b/integration/.mocharc.cjs
index b69283d..bd0980c 100644
--- a/integration/.mocharc.cjs
+++ b/integration/.mocharc.cjs
@@ -1,6 +1,5 @@
-/*
- *
- * @copyright Copyright (c) OX Software GmbH, Germany <info@open-xchange.com>
+/**
+ * @copyright Copyright (c) Open-Xchange GmbH, Germany <info@open-xchange.com>
  * @license AGPL-3.0
  *
  * This code is free software: you can redistribute it and/or modify
@@ -17,7 +16,6 @@
  * along with OX App Suite. If not, see <https://www.gnu.org/licenses/agpl-3.0.txt>.
  *
  * Any use of the work other than as authorized under this license or copyright law is prohibited.
- *
  */
 
 module.exports = {
diff --git a/.eslintrc.cjs b/integration/eslint.config.js
similarity index 71%
rename from .eslintrc.cjs
rename to integration/eslint.config.js
index 6739b0c..64923ba 100644
--- a/.eslintrc.cjs
+++ b/integration/eslint.config.js
@@ -18,25 +18,11 @@
  * Any use of the work other than as authorized under this license or copyright law is prohibited.
  */
 
-const path = require('path')
+import mochaPlugin from 'eslint-plugin-mocha'
 
-module.exports = {
-  root: true,
-  env: {
-    browser: true,
-    es2022: true
-  },
-  extends: [
-    'standard',
-    'plugin:chai-friendly/recommended'
-  ],
-  ignorePatterns: [
-    'public/*'
-  ],
-  rules: {
-    'license-header/header': ['error', path.join(__dirname, 'license-header')]
-  },
-  plugins: [
-    'license-header'
-  ]
-}
+export default [
+  mochaPlugin.configs.flat.recommended,
+  {
+    files: ['integration/**/*_test.js']
+  }
+]
diff --git a/package.json b/package.json
index b472c95..3ba557c 100644
--- a/package.json
+++ b/package.json
@@ -41,14 +41,16 @@
     "prom-client": "^15.1.1"
   },
   "devDependencies": {
+    "@eslint/eslintrc": "^3.0.2",
     "@open-xchange/lint": "^0.0.3",
     "@types/ioredis-mock": "^8.2.5",
     "chai": "^5.1.0",
-    "eslint": "^8.57.0",
+    "eslint": "^9.0.0",
     "eslint-config-standard": "^17.1.0",
     "eslint-plugin-chai-friendly": "^0.7.4",
     "eslint-plugin-import": "^2.29.1",
     "eslint-plugin-license-header": "^0.6.1",
+    "eslint-plugin-mocha": "^10.4.3",
     "eslint-plugin-n": "^17.0.0",
     "eslint-plugin-promise": "^6.1.1",
     "husky": "^9.0.11",
@@ -98,5 +100,13 @@
     "exit": true,
     "recursive": true
   },
-  "packageManager": "pnpm@9.0.5"
+  "packageManager": "pnpm@9.0.5",
+  "pnpm": {
+    "peerDependencyRules": {
+      "allowedVersions": {
+        "eslint": "9",
+        "eslint-plugin-n": "17"
+      }
+    }
+  }
 }
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c6c6189..dac94ac 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -74,6 +74,9 @@ importers:
         specifier: ^15.1.1
         version: 15.1.2
     devDependencies:
+      '@eslint/eslintrc':
+        specifier: ^3.0.2
+        version: 3.0.2
       '@open-xchange/lint':
         specifier: ^0.0.3
         version: 0.0.3
@@ -84,26 +87,29 @@ importers:
         specifier: ^5.1.0
         version: 5.1.0
       eslint:
-        specifier: ^8.57.0
-        version: 8.57.0
+        specifier: ^9.0.0
+        version: 9.1.0
       eslint-config-standard:
         specifier: ^17.1.0
-        version: 17.1.0(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint-plugin-n@17.2.1(eslint@8.57.0))(eslint-plugin-promise@6.1.1(eslint@8.57.0))(eslint@8.57.0)
+        version: 17.1.0(eslint-plugin-import@2.29.1(eslint@9.1.0))(eslint-plugin-n@17.2.1(eslint@9.1.0))(eslint-plugin-promise@6.1.1(eslint@9.1.0))(eslint@9.1.0)
       eslint-plugin-chai-friendly:
         specifier: ^0.7.4
-        version: 0.7.4(eslint@8.57.0)
+        version: 0.7.4(eslint@9.1.0)
       eslint-plugin-import:
         specifier: ^2.29.1
-        version: 2.29.1(eslint@8.57.0)
+        version: 2.29.1(eslint@9.1.0)
       eslint-plugin-license-header:
         specifier: ^0.6.1
         version: 0.6.1
+      eslint-plugin-mocha:
+        specifier: ^10.4.3
+        version: 10.4.3(eslint@9.1.0)
       eslint-plugin-n:
         specifier: ^17.0.0
-        version: 17.2.1(eslint@8.57.0)
+        version: 17.2.1(eslint@9.1.0)
       eslint-plugin-promise:
         specifier: ^6.1.1
-        version: 6.1.1(eslint@8.57.0)
+        version: 6.1.1(eslint@9.1.0)
       husky:
         specifier: ^9.0.11
         version: 9.0.11
@@ -149,10 +155,18 @@ packages:
     resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
 
+  '@eslint/eslintrc@3.0.2':
+    resolution: {integrity: sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
   '@eslint/js@8.57.0':
     resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
 
+  '@eslint/js@9.1.1':
+    resolution: {integrity: sha512-5WoDz3Y19Bg2BnErkZTp0en+c/i9PvgFS7MBe1+m60HjFr0hrphlAGp4yzI7pxpt4xShln4ZyYp4neJm8hmOkQ==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
   '@fastify/accept-negotiator@1.1.0':
     resolution: {integrity: sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==}
     engines: {node: '>=14'}
@@ -203,6 +217,10 @@ packages:
     resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
     engines: {node: '>=10.10.0'}
 
+  '@humanwhocodes/config-array@0.13.0':
+    resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==}
+    engines: {node: '>=10.10.0'}
+
   '@humanwhocodes/module-importer@1.0.1':
     resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
     engines: {node: '>=12.22'}
@@ -210,6 +228,10 @@ packages:
   '@humanwhocodes/object-schema@2.0.3':
     resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
 
+  '@humanwhocodes/retry@0.2.3':
+    resolution: {integrity: sha512-X38nUbachlb01YMlvPFojKoiXq+LzZvuSce70KPMPdeM1Rj03k4dR7lDslhbqXn3Ang4EU3+EAmwEAsbrjHW3g==}
+    engines: {node: '>=18.18'}
+
   '@ioredis/as-callback@3.0.0':
     resolution: {integrity: sha512-Kqv1rZ3WbgOrS+hgzJ5xG5WQuhvzzSTRYvNeyPMLOAM78MHSnuKI20JeJGbpuAt//LCuP0vsexZcorqW7kWhJg==}
 
@@ -742,6 +764,12 @@ packages:
   eslint-plugin-license-header@0.6.1:
     resolution: {integrity: sha512-9aIz8q3OaMr1/uQmCGCWySjTs5nEXUJexNegz/8lluNcZbEl82Ag1Vyr1Hu3oIveRW1NbXDPs6nu4zu9mbrmWA==}
 
+  eslint-plugin-mocha@10.4.3:
+    resolution: {integrity: sha512-emc4TVjq5Ht0/upR+psftuz6IBG5q279p+1dSRDeHf+NS9aaerBi3lXKo1SEzwC29hFIW21gO89CEWSvRsi8IQ==}
+    engines: {node: '>=14.0.0'}
+    peerDependencies:
+      eslint: '>=7.0.0'
+
   eslint-plugin-n@16.6.2:
     resolution: {integrity: sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==}
     engines: {node: '>=16.0.0'}
@@ -764,15 +792,42 @@ packages:
     resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
 
+  eslint-scope@8.0.1:
+    resolution: {integrity: sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+  eslint-utils@3.0.0:
+    resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==}
+    engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0}
+    peerDependencies:
+      eslint: '>=5'
+
+  eslint-visitor-keys@2.1.0:
+    resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==}
+    engines: {node: '>=10'}
+
   eslint-visitor-keys@3.4.3:
     resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
 
+  eslint-visitor-keys@4.0.0:
+    resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
   eslint@8.57.0:
     resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     hasBin: true
 
+  eslint@9.1.0:
+    resolution: {integrity: sha512-1TCBecGFQtItia2o39P7Z4BK1X7ByNPxAiWJvwiyTGcOwYnTiiASgMpNA6a+beu8cFPhEDWvPf6mIlYUJv6sgA==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+    hasBin: true
+
+  espree@10.0.1:
+    resolution: {integrity: sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
   espree@9.6.1:
     resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -866,6 +921,10 @@ packages:
     resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
     engines: {node: ^10.12.0 || >=12.0.0}
 
+  file-entry-cache@8.0.0:
+    resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
+    engines: {node: '>=16.0.0'}
+
   fill-range@7.0.1:
     resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
     engines: {node: '>=8'}
@@ -882,6 +941,10 @@ packages:
     resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==}
     engines: {node: ^10.12.0 || >=12.0.0}
 
+  flat-cache@4.0.1:
+    resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
+    engines: {node: '>=16'}
+
   flat@5.0.2:
     resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==}
     hasBin: true
@@ -1572,6 +1635,9 @@ packages:
   quick-format-unescaped@4.0.4:
     resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
 
+  rambda@7.5.0:
+    resolution: {integrity: sha512-y/M9weqWAH4iopRd7EHDEQQvpFPHj1AA3oHozE9tfITHUtTR7Z9PSlIRRG2l1GuW7sefC1cXFfIcF+cgnShdBA==}
+
   randombytes@2.1.0:
     resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
 
@@ -1985,6 +2051,11 @@ snapshots:
       eslint: 8.57.0
       eslint-visitor-keys: 3.4.3
 
+  '@eslint-community/eslint-utils@4.4.0(eslint@9.1.0)':
+    dependencies:
+      eslint: 9.1.0
+      eslint-visitor-keys: 3.4.3
+
   '@eslint-community/regexpp@4.10.0': {}
 
   '@eslint/eslintrc@2.1.4':
@@ -2001,8 +2072,24 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  '@eslint/eslintrc@3.0.2':
+    dependencies:
+      ajv: 6.12.6
+      debug: 4.3.4(supports-color@8.1.1)
+      espree: 10.0.1
+      globals: 14.0.0
+      ignore: 5.3.1
+      import-fresh: 3.3.0
+      js-yaml: 4.1.0
+      minimatch: 3.1.2
+      strip-json-comments: 3.1.1
+    transitivePeerDependencies:
+      - supports-color
+
   '@eslint/js@8.57.0': {}
 
+  '@eslint/js@9.1.1': {}
+
   '@fastify/accept-negotiator@1.1.0': {}
 
   '@fastify/ajv-compiler@3.5.0':
@@ -2096,10 +2183,20 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  '@humanwhocodes/config-array@0.13.0':
+    dependencies:
+      '@humanwhocodes/object-schema': 2.0.3
+      debug: 4.3.4(supports-color@8.1.1)
+      minimatch: 3.1.2
+    transitivePeerDependencies:
+      - supports-color
+
   '@humanwhocodes/module-importer@1.0.1': {}
 
   '@humanwhocodes/object-schema@2.0.3': {}
 
+  '@humanwhocodes/retry@0.2.3': {}
+
   '@ioredis/as-callback@3.0.0': {}
 
   '@ioredis/commands@1.2.0': {}
@@ -2628,6 +2725,11 @@ snapshots:
       eslint: 8.57.0
       semver: 7.6.0
 
+  eslint-compat-utils@0.5.0(eslint@9.1.0):
+    dependencies:
+      eslint: 9.1.0
+      semver: 7.6.0
+
   eslint-config-standard@17.1.0(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint-plugin-n@16.6.2(eslint@8.57.0))(eslint-plugin-promise@6.1.1(eslint@8.57.0))(eslint@8.57.0):
     dependencies:
       eslint: 8.57.0
@@ -2635,12 +2737,12 @@ snapshots:
       eslint-plugin-n: 16.6.2(eslint@8.57.0)
       eslint-plugin-promise: 6.1.1(eslint@8.57.0)
 
-  eslint-config-standard@17.1.0(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint-plugin-n@17.2.1(eslint@8.57.0))(eslint-plugin-promise@6.1.1(eslint@8.57.0))(eslint@8.57.0):
+  eslint-config-standard@17.1.0(eslint-plugin-import@2.29.1(eslint@9.1.0))(eslint-plugin-n@17.2.1(eslint@9.1.0))(eslint-plugin-promise@6.1.1(eslint@9.1.0))(eslint@9.1.0):
     dependencies:
-      eslint: 8.57.0
-      eslint-plugin-import: 2.29.1(eslint@8.57.0)
-      eslint-plugin-n: 17.2.1(eslint@8.57.0)
-      eslint-plugin-promise: 6.1.1(eslint@8.57.0)
+      eslint: 9.1.0
+      eslint-plugin-import: 2.29.1(eslint@9.1.0)
+      eslint-plugin-n: 17.2.1(eslint@9.1.0)
+      eslint-plugin-promise: 6.1.1(eslint@9.1.0)
 
   eslint-import-resolver-node@0.3.9:
     dependencies:
@@ -2659,10 +2761,23 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  eslint-module-utils@2.8.1(eslint-import-resolver-node@0.3.9)(eslint@9.1.0):
+    dependencies:
+      debug: 4.3.4(supports-color@8.1.1)
+    optionalDependencies:
+      eslint: 9.1.0
+      eslint-import-resolver-node: 0.3.9
+    transitivePeerDependencies:
+      - supports-color
+
   eslint-plugin-chai-friendly@0.7.4(eslint@8.57.0):
     dependencies:
       eslint: 8.57.0
 
+  eslint-plugin-chai-friendly@0.7.4(eslint@9.1.0):
+    dependencies:
+      eslint: 9.1.0
+
   eslint-plugin-codeceptjs@1.3.0:
     dependencies:
       requireindex: 1.1.0
@@ -2674,6 +2789,13 @@ snapshots:
       eslint: 8.57.0
       eslint-compat-utils: 0.5.0(eslint@8.57.0)
 
+  eslint-plugin-es-x@7.6.0(eslint@9.1.0):
+    dependencies:
+      '@eslint-community/eslint-utils': 4.4.0(eslint@9.1.0)
+      '@eslint-community/regexpp': 4.10.0
+      eslint: 9.1.0
+      eslint-compat-utils: 0.5.0(eslint@9.1.0)
+
   eslint-plugin-import@2.29.1(eslint@8.57.0):
     dependencies:
       array-includes: 3.1.8
@@ -2699,10 +2821,42 @@ snapshots:
       - eslint-import-resolver-webpack
       - supports-color
 
+  eslint-plugin-import@2.29.1(eslint@9.1.0):
+    dependencies:
+      array-includes: 3.1.8
+      array.prototype.findlastindex: 1.2.5
+      array.prototype.flat: 1.3.2
+      array.prototype.flatmap: 1.3.2
+      debug: 4.3.4(supports-color@8.1.1)
+      doctrine: 2.1.0
+      eslint: 9.1.0
+      eslint-import-resolver-node: 0.3.9
+      eslint-module-utils: 2.8.1(eslint-import-resolver-node@0.3.9)(eslint@9.1.0)
+      hasown: 2.0.2
+      is-core-module: 2.13.1
+      is-glob: 4.0.3
+      minimatch: 3.1.2
+      object.fromentries: 2.0.8
+      object.groupby: 1.0.3
+      object.values: 1.2.0
+      semver: 7.6.0
+      tsconfig-paths: 3.15.0
+    transitivePeerDependencies:
+      - eslint-import-resolver-typescript
+      - eslint-import-resolver-webpack
+      - supports-color
+
   eslint-plugin-license-header@0.6.1:
     dependencies:
       requireindex: 1.2.0
 
+  eslint-plugin-mocha@10.4.3(eslint@9.1.0):
+    dependencies:
+      eslint: 9.1.0
+      eslint-utils: 3.0.0(eslint@9.1.0)
+      globals: 13.24.0
+      rambda: 7.5.0
+
   eslint-plugin-n@16.6.2(eslint@8.57.0):
     dependencies:
       '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
@@ -2718,12 +2872,12 @@ snapshots:
       resolve: 1.22.8
       semver: 7.6.0
 
-  eslint-plugin-n@17.2.1(eslint@8.57.0):
+  eslint-plugin-n@17.2.1(eslint@9.1.0):
     dependencies:
-      '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+      '@eslint-community/eslint-utils': 4.4.0(eslint@9.1.0)
       enhanced-resolve: 5.16.0
-      eslint: 8.57.0
-      eslint-plugin-es-x: 7.6.0(eslint@8.57.0)
+      eslint: 9.1.0
+      eslint-plugin-es-x: 7.6.0(eslint@9.1.0)
       get-tsconfig: 4.7.3
       globals: 14.0.0
       ignore: 5.3.1
@@ -2734,13 +2888,31 @@ snapshots:
     dependencies:
       eslint: 8.57.0
 
+  eslint-plugin-promise@6.1.1(eslint@9.1.0):
+    dependencies:
+      eslint: 9.1.0
+
   eslint-scope@7.2.2:
     dependencies:
       esrecurse: 4.3.0
       estraverse: 5.3.0
 
+  eslint-scope@8.0.1:
+    dependencies:
+      esrecurse: 4.3.0
+      estraverse: 5.3.0
+
+  eslint-utils@3.0.0(eslint@9.1.0):
+    dependencies:
+      eslint: 9.1.0
+      eslint-visitor-keys: 2.1.0
+
+  eslint-visitor-keys@2.1.0: {}
+
   eslint-visitor-keys@3.4.3: {}
 
+  eslint-visitor-keys@4.0.0: {}
+
   eslint@8.57.0:
     dependencies:
       '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
@@ -2784,6 +2956,51 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  eslint@9.1.0:
+    dependencies:
+      '@eslint-community/eslint-utils': 4.4.0(eslint@9.1.0)
+      '@eslint-community/regexpp': 4.10.0
+      '@eslint/eslintrc': 3.0.2
+      '@eslint/js': 9.1.1
+      '@humanwhocodes/config-array': 0.13.0
+      '@humanwhocodes/module-importer': 1.0.1
+      '@humanwhocodes/retry': 0.2.3
+      '@nodelib/fs.walk': 1.2.8
+      ajv: 6.12.6
+      chalk: 4.1.2
+      cross-spawn: 7.0.3
+      debug: 4.3.4(supports-color@8.1.1)
+      escape-string-regexp: 4.0.0
+      eslint-scope: 8.0.1
+      eslint-visitor-keys: 4.0.0
+      espree: 10.0.1
+      esquery: 1.5.0
+      esutils: 2.0.3
+      fast-deep-equal: 3.1.3
+      file-entry-cache: 8.0.0
+      find-up: 5.0.0
+      glob-parent: 6.0.2
+      ignore: 5.3.1
+      imurmurhash: 0.1.4
+      is-glob: 4.0.3
+      is-path-inside: 3.0.3
+      json-stable-stringify-without-jsonify: 1.0.1
+      levn: 0.4.1
+      lodash.merge: 4.6.2
+      minimatch: 3.1.2
+      natural-compare: 1.4.0
+      optionator: 0.9.3
+      strip-ansi: 6.0.1
+      text-table: 0.2.0
+    transitivePeerDependencies:
+      - supports-color
+
+  espree@10.0.1:
+    dependencies:
+      acorn: 8.11.3
+      acorn-jsx: 5.3.2(acorn@8.11.3)
+      eslint-visitor-keys: 4.0.0
+
   espree@9.6.1:
     dependencies:
       acorn: 8.11.3
@@ -2899,6 +3116,10 @@ snapshots:
     dependencies:
       flat-cache: 3.2.0
 
+  file-entry-cache@8.0.0:
+    dependencies:
+      flat-cache: 4.0.1
+
   fill-range@7.0.1:
     dependencies:
       to-regex-range: 5.0.1
@@ -2920,6 +3141,11 @@ snapshots:
       keyv: 4.5.4
       rimraf: 3.0.2
 
+  flat-cache@4.0.1:
+    dependencies:
+      flatted: 3.3.1
+      keyv: 4.5.4
+
   flat@5.0.2: {}
 
   flatted@3.3.1: {}
@@ -3623,6 +3849,8 @@ snapshots:
 
   quick-format-unescaped@4.0.4: {}
 
+  rambda@7.5.0: {}
+
   randombytes@2.1.0:
     dependencies:
       safe-buffer: 5.2.1
diff --git a/spec/.eslintrc b/spec/.eslintrc
deleted file mode 100644
index 7eeefc3..0000000
--- a/spec/.eslintrc
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "env": {
-    "mocha": true
-  }
-}
diff --git a/spec/.mocharc.cjs b/spec/.mocharc.cjs
index d70754b..1eb9353 100644
--- a/spec/.mocharc.cjs
+++ b/spec/.mocharc.cjs
@@ -1,6 +1,5 @@
-/*
- *
- * @copyright Copyright (c) OX Software GmbH, Germany <info@open-xchange.com>
+/**
+ * @copyright Copyright (c) Open-Xchange GmbH, Germany <info@open-xchange.com>
  * @license AGPL-3.0
  *
  * This code is free software: you can redistribute it and/or modify
@@ -17,9 +16,8 @@
  * along with OX App Suite. If not, see <https://www.gnu.org/licenses/agpl-3.0.txt>.
  *
  * Any use of the work other than as authorized under this license or copyright law is prohibited.
- *
  */
 
 module.exports = {
-  spec: ['spec/**/*_test.js'],
+  spec: ['spec/**/*_test.js']
 }
diff --git a/spec/eslint.config.js b/spec/eslint.config.js
new file mode 100644
index 0000000..8264e3c
--- /dev/null
+++ b/spec/eslint.config.js
@@ -0,0 +1,28 @@
+/**
+ * @copyright Copyright (c) Open-Xchange GmbH, Germany <info@open-xchange.com>
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with OX App Suite. If not, see <https://www.gnu.org/licenses/agpl-3.0.txt>.
+ *
+ * Any use of the work other than as authorized under this license or copyright law is prohibited.
+ */
+
+import mochaPlugin from 'eslint-plugin-mocha'
+
+export default [
+  mochaPlugin.configs.flat.recommended,
+  {
+    files: ['spec/**/*_test.js']
+  }
+]
diff --git a/spec/pwa_test.js b/spec/pwa_test.js
index 2590e7b..4db32fa 100644
--- a/spec/pwa_test.js
+++ b/spec/pwa_test.js
@@ -24,6 +24,7 @@ import { injectApp, mockConfig, mockFetch, mockRedis } from './util.js'
 
 describe('Service delivers a generated web-manifest', function () {
   let app
+
   before(async function () {
     await mockConfig({ urls: ['http://ui-server/'] })
     await mockRedis()
diff --git a/spec/util_test.js b/spec/util_test.js
index 94f5e81..1fdf6de 100644
--- a/spec/util_test.js
+++ b/spec/util_test.js
@@ -53,6 +53,7 @@ describe('Util', function () {
 
   describe('asyncThrottle function', function () {
     let spy
+
     beforeEach(function () {
       spy = sandbox.spy(function () {
         return new Promise((resolve, reject) => {
-- 
GitLab