diff --git a/CHANGELOG.md b/CHANGELOG.md
index 37eb4717d845a3e30b899c51f370df178a5286b0..d3e391ae70a1cd4421d66db1374476dda1ce213e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,7 +18,13 @@
 -->
 
 
-## 3.4.2 (???)
+## 3.5.0 (???)
+
+### ✨ Feature
+- Link a commit of an exercise as a corrige of an assignment
+
+
+## 3.4.2 (2023-01-23)
 
 ### 📚 Documentation
 - Wiki: add tutorial about adding a new route to the API
diff --git a/ExpressAPI/assets/OpenAPI/OpenAPI.yaml b/ExpressAPI/assets/OpenAPI/OpenAPI.yaml
index 2bbe1d3a26375c79d0b02d84bb0773b74d13712c..b4d9846f36a75a1b46f1a023543eb92c7137588f 100644
--- a/ExpressAPI/assets/OpenAPI/OpenAPI.yaml
+++ b/ExpressAPI/assets/OpenAPI/OpenAPI.yaml
@@ -1,7 +1,7 @@
 openapi: 3.1.0
 info:
     title: Dojo API
-    version: 3.4.2
+    version: 3.5.0
     description: |
         **Backend API of the Dojo project.**
         
diff --git a/ExpressAPI/package-lock.json b/ExpressAPI/package-lock.json
index 1d604113f07fdc5580d75b90d5b264f8a0fb799f..d336b37dafae0bb7143c963521dcac32fb6d332b 100644
--- a/ExpressAPI/package-lock.json
+++ b/ExpressAPI/package-lock.json
@@ -1,19 +1,20 @@
 {
     "name": "dojo_backend_api",
-    "version": "3.4.2",
+    "version": "3.5.0",
     "lockfileVersion": 3,
     "requires": true,
     "packages": {
         "": {
             "name": "dojo_backend_api",
-            "version": "3.4.2",
+            "version": "3.5.0",
             "license": "AGPLv3",
             "dependencies": {
-                "@prisma/client": "^5.8.1",
-                "axios": "^1.6.5",
+                "@gitbeaker/rest": "^39.34.2",
+                "@prisma/client": "^5.9.1",
+                "axios": "^1.6.7",
                 "compression": "^1.7.4",
                 "cors": "^2.8.5",
-                "dotenv": "^16.3.1",
+                "dotenv": "^16.4.1",
                 "dotenv-expand": "^10.0.0",
                 "express": "^4.18.2",
                 "express-validator": "^7.0.1",
@@ -25,38 +26,38 @@
                 "morgan": "^1.10.0",
                 "multer": "^1.4.5-lts.1",
                 "mysql": "^2.18.1",
-                "node": "^20.10.0",
+                "node": "^20.11.0",
                 "parse-link-header": "^2.0.0",
-                "semver": "^7.5.4",
+                "semver": "^7.6.0",
                 "swagger-ui-express": "^5.0.0",
-                "tar-stream": "^3.1.6",
+                "tar-stream": "^3.1.7",
                 "uuid": "^9.0.1",
                 "winston": "^3.11.0",
                 "zod": "^3.22.4",
                 "zod-validation-error": "^3.0.0"
             },
             "devDependencies": {
-                "@redocly/cli": "^1.6.0",
+                "@redocly/cli": "^1.8.2",
                 "@types/compression": "^1.7.5",
                 "@types/cors": "^2.8.17",
                 "@types/express": "^4.17.21",
                 "@types/jsonwebtoken": "^9.0.5",
                 "@types/morgan": "^1.9.9",
                 "@types/multer": "^1.4.11",
-                "@types/node": "^20.11.5",
+                "@types/node": "^20.11.17",
                 "@types/parse-link-header": "^2.0.3",
                 "@types/semver": "^7.5.6",
                 "@types/swagger-ui-express": "^4.1.6",
                 "@types/tar-stream": "^3.1.3",
-                "@types/uuid": "^9.0.7",
-                "@typescript-eslint/eslint-plugin": "^6.18.1",
-                "@typescript-eslint/parser": "^6.18.1",
+                "@types/uuid": "^9.0.8",
+                "@typescript-eslint/eslint-plugin": "^6.21.0",
+                "@typescript-eslint/parser": "^6.21.0",
                 "dotenv-cli": "^7.3.0",
-                "dotenv-vault": "^1.25.0",
+                "dotenv-vault": "^1.26.0",
                 "genversion": "^3.2.0",
                 "nodemon": "^3.0.3",
-                "npm": "^10.3.0",
-                "prisma": "^5.8.1",
+                "npm": "^10.4.0",
+                "prisma": "^5.9.1",
                 "ts-node": "^10.9.2",
                 "typescript": "^5.3.3"
             }
@@ -72,9 +73,9 @@
             }
         },
         "node_modules/@babel/runtime": {
-            "version": "7.23.8",
-            "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz",
-            "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==",
+            "version": "7.23.9",
+            "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz",
+            "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==",
             "dev": true,
             "dependencies": {
                 "regenerator-runtime": "^0.14.0"
@@ -222,6 +223,73 @@
             "integrity": "sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==",
             "dev": true
         },
+        "node_modules/@gitbeaker/core": {
+            "version": "39.34.2",
+            "resolved": "https://registry.npmjs.org/@gitbeaker/core/-/core-39.34.2.tgz",
+            "integrity": "sha512-Vs1BKnEMnHltq1nMuBKxust1E+JUroDVKLy87ElLgvjAkH726mEVJCFnNC2/o2Ru7Et2qqhFN+PlUeYzzAbU2w==",
+            "dependencies": {
+                "@gitbeaker/requester-utils": "^39.34.2",
+                "qs": "^6.11.2",
+                "xcase": "^2.0.1"
+            },
+            "engines": {
+                "node": ">=18.0.0"
+            }
+        },
+        "node_modules/@gitbeaker/core/node_modules/qs": {
+            "version": "6.11.2",
+            "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz",
+            "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==",
+            "dependencies": {
+                "side-channel": "^1.0.4"
+            },
+            "engines": {
+                "node": ">=0.6"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
+        "node_modules/@gitbeaker/requester-utils": {
+            "version": "39.34.2",
+            "resolved": "https://registry.npmjs.org/@gitbeaker/requester-utils/-/requester-utils-39.34.2.tgz",
+            "integrity": "sha512-ToCwNKQe/+uHjB2kPTXY72SvbAyjsPABb9T1EiMGuVahk6rWdhtVZIM659rGuqdJGTqQ4y18wk0A+w6D3Z2lCQ==",
+            "dependencies": {
+                "picomatch-browser": "^2.2.6",
+                "qs": "^6.11.2",
+                "rate-limiter-flexible": "^4.0.0",
+                "xcase": "^2.0.1"
+            },
+            "engines": {
+                "node": ">=18.0.0"
+            }
+        },
+        "node_modules/@gitbeaker/requester-utils/node_modules/qs": {
+            "version": "6.11.2",
+            "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz",
+            "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==",
+            "dependencies": {
+                "side-channel": "^1.0.4"
+            },
+            "engines": {
+                "node": ">=0.6"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
+        "node_modules/@gitbeaker/rest": {
+            "version": "39.34.2",
+            "resolved": "https://registry.npmjs.org/@gitbeaker/rest/-/rest-39.34.2.tgz",
+            "integrity": "sha512-MT4Vue1ltvsR7Nug18A6DIk+u+gu64+b0Un/R2XIsLB7eSAX8Pm/sQnYxsjHksroZJVlyGHiGsaxbllX75Pntg==",
+            "dependencies": {
+                "@gitbeaker/core": "^39.34.2",
+                "@gitbeaker/requester-utils": "^39.34.2"
+            },
+            "engines": {
+                "node": ">=18.0.0"
+            }
+        },
         "node_modules/@humanwhocodes/config-array": {
             "version": "0.11.14",
             "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
@@ -723,15 +791,16 @@
             "version": "3.0.8",
             "resolved": "https://registry.npmjs.org/@oclif/screen/-/screen-3.0.8.tgz",
             "integrity": "sha512-yx6KAqlt3TAHBduS2fMQtJDL2ufIHnDRArrJEOoTTuizxqmjLT+psGYOHpmMl3gvQpFJ11Hs76guUUktzAF9Bg==",
+            "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
             "dev": true,
             "engines": {
                 "node": ">=12.0.0"
             }
         },
         "node_modules/@prisma/client": {
-            "version": "5.8.1",
-            "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.8.1.tgz",
-            "integrity": "sha512-xQtMPfbIwLlbm0VVIVQY2yqQVOxPwRQhvIp7Z3m2900g1bu/zRHKhYZJQWELqmjl6d8YwBy0K2NvMqh47v1ubw==",
+            "version": "5.9.1",
+            "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.9.1.tgz",
+            "integrity": "sha512-caSOnG4kxcSkhqC/2ShV7rEoWwd3XrftokxJqOCMVvia4NYV/TPtJlS9C2os3Igxw/Qyxumj9GBQzcStzECvtQ==",
             "hasInstallScript": true,
             "engines": {
                 "node": ">=16.13"
@@ -746,48 +815,48 @@
             }
         },
         "node_modules/@prisma/debug": {
-            "version": "5.8.1",
-            "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.8.1.tgz",
-            "integrity": "sha512-tjuw7eA0Us3T42jx9AmAgL58rzwzpFGYc3R7Y4Ip75EBYrKMBA1YihuWMcBC92ILmjlQ/u3p8VxcIE0hr+fZfg==",
+            "version": "5.9.1",
+            "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.9.1.tgz",
+            "integrity": "sha512-yAHFSFCg8KVoL0oRUno3m60GAjsUKYUDkQ+9BA2X2JfVR3kRVSJFc/GpQ2fSORi4pSHZR9orfM4UC9OVXIFFTA==",
             "devOptional": true
         },
         "node_modules/@prisma/engines": {
-            "version": "5.8.1",
-            "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.8.1.tgz",
-            "integrity": "sha512-TJgYLRrZr56uhqcXO4GmP5be+zjCIHtLDK20Cnfg+o9d905hsN065QOL+3Z0zQAy6YD31Ol4u2kzSfRmbJv/uA==",
+            "version": "5.9.1",
+            "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.9.1.tgz",
+            "integrity": "sha512-gkdXmjxQ5jktxWNdDA5aZZ6R8rH74JkoKq6LD5mACSvxd2vbqWeWIOV0Py5wFC8vofOYShbt6XUeCIUmrOzOnQ==",
             "devOptional": true,
             "hasInstallScript": true,
             "dependencies": {
-                "@prisma/debug": "5.8.1",
-                "@prisma/engines-version": "5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2",
-                "@prisma/fetch-engine": "5.8.1",
-                "@prisma/get-platform": "5.8.1"
+                "@prisma/debug": "5.9.1",
+                "@prisma/engines-version": "5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64",
+                "@prisma/fetch-engine": "5.9.1",
+                "@prisma/get-platform": "5.9.1"
             }
         },
         "node_modules/@prisma/engines-version": {
-            "version": "5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2",
-            "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2.tgz",
-            "integrity": "sha512-f5C3JM3l9yhGr3cr4FMqWloFaSCpNpMi58Om22rjD2DOz3owci2mFdFXMgnAGazFPKrCbbEhcxdsRfspEYRoFQ==",
+            "version": "5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64",
+            "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64.tgz",
+            "integrity": "sha512-HFl7275yF0FWbdcNvcSRbbu9JCBSLMcurYwvWc8WGDnpu7APxQo2ONtZrUggU3WxLxUJ2uBX+0GOFIcJeVeOOQ==",
             "devOptional": true
         },
         "node_modules/@prisma/fetch-engine": {
-            "version": "5.8.1",
-            "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.8.1.tgz",
-            "integrity": "sha512-+bgjjoSFa6uYEbAPlklfoVSStOEfcpheOjoBoNsNNSQdSzcwE2nM4Q0prun0+P8/0sCHo18JZ9xqa8gObvgOUw==",
+            "version": "5.9.1",
+            "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.9.1.tgz",
+            "integrity": "sha512-l0goQOMcNVOJs1kAcwqpKq3ylvkD9F04Ioe1oJoCqmz05mw22bNAKKGWuDd3zTUoUZr97va0c/UfLNru+PDmNA==",
             "devOptional": true,
             "dependencies": {
-                "@prisma/debug": "5.8.1",
-                "@prisma/engines-version": "5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2",
-                "@prisma/get-platform": "5.8.1"
+                "@prisma/debug": "5.9.1",
+                "@prisma/engines-version": "5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64",
+                "@prisma/get-platform": "5.9.1"
             }
         },
         "node_modules/@prisma/get-platform": {
-            "version": "5.8.1",
-            "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.8.1.tgz",
-            "integrity": "sha512-wnA+6HTFcY+tkykMokix9GiAkaauPC5W/gg0O5JB0J8tCTNWrqpnQ7AsaGRfkYUbeOIioh6woDjQrGTTRf1Zag==",
+            "version": "5.9.1",
+            "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.9.1.tgz",
+            "integrity": "sha512-6OQsNxTyhvG+T2Ksr8FPFpuPeL4r9u0JF0OZHUBI/Uy9SS43sPyAIutt4ZEAyqWQt104ERh70EZedkHZKsnNbg==",
             "devOptional": true,
             "dependencies": {
-                "@prisma/debug": "5.8.1"
+                "@prisma/debug": "5.9.1"
             }
         },
         "node_modules/@redocly/ajv": {
@@ -807,15 +876,17 @@
             }
         },
         "node_modules/@redocly/cli": {
-            "version": "1.6.0",
-            "resolved": "https://registry.npmjs.org/@redocly/cli/-/cli-1.6.0.tgz",
-            "integrity": "sha512-0naVFJGR2tVcpMIHSFRr2HAoyy70qMqDAP6kXcnOdkGkwLRJ8s/5n1STwsym/yZwNkhrt2M0cKT6KAMlTUeCeg==",
+            "version": "1.8.2",
+            "resolved": "https://registry.npmjs.org/@redocly/cli/-/cli-1.8.2.tgz",
+            "integrity": "sha512-HrdLlCEOrHEZGdm2dYcgUaNb7o0Nga7sX+a3us/M0ixHrQ0GMlGcxAphB+Cxylud+MpIdEQ3eoEVJ/clFRa1Zw==",
             "dev": true,
             "dependencies": {
-                "@redocly/openapi-core": "1.6.0",
+                "@redocly/openapi-core": "1.8.2",
+                "abort-controller": "^3.0.0",
                 "chokidar": "^3.5.1",
                 "colorette": "^1.2.0",
                 "core-js": "^3.32.1",
+                "form-data": "^4.0.0",
                 "get-port-please": "^3.0.1",
                 "glob": "^7.1.6",
                 "handlebars": "^4.7.6",
@@ -839,13 +910,12 @@
             }
         },
         "node_modules/@redocly/openapi-core": {
-            "version": "1.6.0",
-            "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.6.0.tgz",
-            "integrity": "sha512-oao6Aey4peLKfagzWGb6N7OBI6CoDWEP4ka/XjrUNZw+UoKVVg3hVBXW4Vr3CJ2O8j6wEa2i+Lbb92VQQsoxwg==",
+            "version": "1.8.2",
+            "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.8.2.tgz",
+            "integrity": "sha512-VjUz3wrqcDbO1HfEB0AUzh6Y7T1jNJR4Jmgfs0ipuoipLjU5bDsdfKJGSSz2u0WpfmqklPsd11ynkgL5Y+MlCg==",
             "dev": true,
             "dependencies": {
                 "@redocly/ajv": "^8.11.0",
-                "@types/node": "^14.11.8",
                 "colorette": "^1.2.0",
                 "js-levenshtein": "^1.1.6",
                 "js-yaml": "^4.1.0",
@@ -860,12 +930,6 @@
                 "npm": ">=7.0.0"
             }
         },
-        "node_modules/@redocly/openapi-core/node_modules/@types/node": {
-            "version": "14.18.63",
-            "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz",
-            "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==",
-            "dev": true
-        },
         "node_modules/@tsconfig/node10": {
             "version": "1.0.9",
             "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
@@ -949,9 +1013,9 @@
             }
         },
         "node_modules/@types/express-serve-static-core": {
-            "version": "4.17.41",
-            "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz",
-            "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==",
+            "version": "4.17.43",
+            "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz",
+            "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==",
             "dev": true,
             "dependencies": {
                 "@types/node": "*",
@@ -1006,9 +1070,9 @@
             }
         },
         "node_modules/@types/node": {
-            "version": "20.11.5",
-            "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.5.tgz",
-            "integrity": "sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==",
+            "version": "20.11.17",
+            "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.17.tgz",
+            "integrity": "sha512-QmgQZGWu1Yw9TDyAP9ZzpFJKynYNeOvwMJmaxABfieQoVoiVOS6MN1WSpqpRcbeA5+RW82kraAVxCCJg+780Qw==",
             "dev": true,
             "dependencies": {
                 "undici-types": "~5.26.4"
@@ -1090,22 +1154,22 @@
             "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="
         },
         "node_modules/@types/uuid": {
-            "version": "9.0.7",
-            "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.7.tgz",
-            "integrity": "sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g==",
+            "version": "9.0.8",
+            "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz",
+            "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==",
             "dev": true
         },
         "node_modules/@typescript-eslint/eslint-plugin": {
-            "version": "6.19.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.19.0.tgz",
-            "integrity": "sha512-DUCUkQNklCQYnrBSSikjVChdc84/vMPDQSgJTHBZ64G9bA9w0Crc0rd2diujKbTdp6w2J47qkeHQLoi0rpLCdg==",
+            "version": "6.21.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz",
+            "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==",
             "dev": true,
             "dependencies": {
                 "@eslint-community/regexpp": "^4.5.1",
-                "@typescript-eslint/scope-manager": "6.19.0",
-                "@typescript-eslint/type-utils": "6.19.0",
-                "@typescript-eslint/utils": "6.19.0",
-                "@typescript-eslint/visitor-keys": "6.19.0",
+                "@typescript-eslint/scope-manager": "6.21.0",
+                "@typescript-eslint/type-utils": "6.21.0",
+                "@typescript-eslint/utils": "6.21.0",
+                "@typescript-eslint/visitor-keys": "6.21.0",
                 "debug": "^4.3.4",
                 "graphemer": "^1.4.0",
                 "ignore": "^5.2.4",
@@ -1131,15 +1195,15 @@
             }
         },
         "node_modules/@typescript-eslint/parser": {
-            "version": "6.19.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.19.0.tgz",
-            "integrity": "sha512-1DyBLG5SH7PYCd00QlroiW60YJ4rWMuUGa/JBV0iZuqi4l4IK3twKPq5ZkEebmGqRjXWVgsUzfd3+nZveewgow==",
+            "version": "6.21.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz",
+            "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==",
             "dev": true,
             "dependencies": {
-                "@typescript-eslint/scope-manager": "6.19.0",
-                "@typescript-eslint/types": "6.19.0",
-                "@typescript-eslint/typescript-estree": "6.19.0",
-                "@typescript-eslint/visitor-keys": "6.19.0",
+                "@typescript-eslint/scope-manager": "6.21.0",
+                "@typescript-eslint/types": "6.21.0",
+                "@typescript-eslint/typescript-estree": "6.21.0",
+                "@typescript-eslint/visitor-keys": "6.21.0",
                 "debug": "^4.3.4"
             },
             "engines": {
@@ -1159,13 +1223,13 @@
             }
         },
         "node_modules/@typescript-eslint/scope-manager": {
-            "version": "6.19.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.0.tgz",
-            "integrity": "sha512-dO1XMhV2ehBI6QN8Ufi7I10wmUovmLU0Oru3n5LVlM2JuzB4M+dVphCPLkVpKvGij2j/pHBWuJ9piuXx+BhzxQ==",
+            "version": "6.21.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz",
+            "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==",
             "dev": true,
             "dependencies": {
-                "@typescript-eslint/types": "6.19.0",
-                "@typescript-eslint/visitor-keys": "6.19.0"
+                "@typescript-eslint/types": "6.21.0",
+                "@typescript-eslint/visitor-keys": "6.21.0"
             },
             "engines": {
                 "node": "^16.0.0 || >=18.0.0"
@@ -1176,13 +1240,13 @@
             }
         },
         "node_modules/@typescript-eslint/type-utils": {
-            "version": "6.19.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.19.0.tgz",
-            "integrity": "sha512-mcvS6WSWbjiSxKCwBcXtOM5pRkPQ6kcDds/juxcy/727IQr3xMEcwr/YLHW2A2+Fp5ql6khjbKBzOyjuPqGi/w==",
+            "version": "6.21.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz",
+            "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==",
             "dev": true,
             "dependencies": {
-                "@typescript-eslint/typescript-estree": "6.19.0",
-                "@typescript-eslint/utils": "6.19.0",
+                "@typescript-eslint/typescript-estree": "6.21.0",
+                "@typescript-eslint/utils": "6.21.0",
                 "debug": "^4.3.4",
                 "ts-api-utils": "^1.0.1"
             },
@@ -1203,9 +1267,9 @@
             }
         },
         "node_modules/@typescript-eslint/types": {
-            "version": "6.19.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.0.tgz",
-            "integrity": "sha512-lFviGV/vYhOy3m8BJ/nAKoAyNhInTdXpftonhWle66XHAtT1ouBlkjL496b5H5hb8dWXHwtypTqgtb/DEa+j5A==",
+            "version": "6.21.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz",
+            "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==",
             "dev": true,
             "engines": {
                 "node": "^16.0.0 || >=18.0.0"
@@ -1216,13 +1280,13 @@
             }
         },
         "node_modules/@typescript-eslint/typescript-estree": {
-            "version": "6.19.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.0.tgz",
-            "integrity": "sha512-o/zefXIbbLBZ8YJ51NlkSAt2BamrK6XOmuxSR3hynMIzzyMY33KuJ9vuMdFSXW+H0tVvdF9qBPTHA91HDb4BIQ==",
+            "version": "6.21.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz",
+            "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==",
             "dev": true,
             "dependencies": {
-                "@typescript-eslint/types": "6.19.0",
-                "@typescript-eslint/visitor-keys": "6.19.0",
+                "@typescript-eslint/types": "6.21.0",
+                "@typescript-eslint/visitor-keys": "6.21.0",
                 "debug": "^4.3.4",
                 "globby": "^11.1.0",
                 "is-glob": "^4.0.3",
@@ -1259,17 +1323,17 @@
             }
         },
         "node_modules/@typescript-eslint/utils": {
-            "version": "6.19.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.19.0.tgz",
-            "integrity": "sha512-QR41YXySiuN++/dC9UArYOg4X86OAYP83OWTewpVx5ct1IZhjjgTLocj7QNxGhWoTqknsgpl7L+hGygCO+sdYw==",
+            "version": "6.21.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz",
+            "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==",
             "dev": true,
             "dependencies": {
                 "@eslint-community/eslint-utils": "^4.4.0",
                 "@types/json-schema": "^7.0.12",
                 "@types/semver": "^7.5.0",
-                "@typescript-eslint/scope-manager": "6.19.0",
-                "@typescript-eslint/types": "6.19.0",
-                "@typescript-eslint/typescript-estree": "6.19.0",
+                "@typescript-eslint/scope-manager": "6.21.0",
+                "@typescript-eslint/types": "6.21.0",
+                "@typescript-eslint/typescript-estree": "6.21.0",
                 "semver": "^7.5.4"
             },
             "engines": {
@@ -1284,12 +1348,12 @@
             }
         },
         "node_modules/@typescript-eslint/visitor-keys": {
-            "version": "6.19.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.0.tgz",
-            "integrity": "sha512-hZaUCORLgubBvtGpp1JEFEazcuEdfxta9j4iUwdSAr7mEsYYAp3EAUyCZk3VEEqGj6W+AV4uWyrDGtrlawAsgQ==",
+            "version": "6.21.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz",
+            "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==",
             "dev": true,
             "dependencies": {
-                "@typescript-eslint/types": "6.19.0",
+                "@typescript-eslint/types": "6.21.0",
                 "eslint-visitor-keys": "^3.4.1"
             },
             "engines": {
@@ -1313,6 +1377,18 @@
             "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
             "dev": true
         },
+        "node_modules/abort-controller": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+            "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+            "dev": true,
+            "dependencies": {
+                "event-target-shim": "^5.0.0"
+            },
+            "engines": {
+                "node": ">=6.5"
+            }
+        },
         "node_modules/accepts": {
             "version": "1.3.8",
             "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@@ -1498,9 +1574,9 @@
             }
         },
         "node_modules/axios": {
-            "version": "1.6.5",
-            "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
-            "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
+            "version": "1.6.7",
+            "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz",
+            "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==",
             "dependencies": {
                 "follow-redirects": "^1.15.4",
                 "form-data": "^4.0.0",
@@ -1508,9 +1584,9 @@
             }
         },
         "node_modules/b4a": {
-            "version": "1.6.4",
-            "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz",
-            "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw=="
+            "version": "1.6.6",
+            "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz",
+            "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg=="
         },
         "node_modules/balanced-match": {
             "version": "1.0.2",
@@ -1518,6 +1594,12 @@
             "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
             "dev": true
         },
+        "node_modules/bare-events": {
+            "version": "2.2.0",
+            "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.0.tgz",
+            "integrity": "sha512-Yyyqff4PIFfSuthCZqLlPISTWHmnQxoPuAvkmgzsJEmG3CesdIv6Xweayl0JkCZJSB2yYIdJyEz97tpxNhgjbg==",
+            "optional": true
+        },
         "node_modules/base64-js": {
             "version": "1.5.1",
             "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -1719,13 +1801,17 @@
             }
         },
         "node_modules/call-bind": {
-            "version": "1.0.5",
-            "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz",
-            "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==",
+            "version": "1.0.6",
+            "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.6.tgz",
+            "integrity": "sha512-Mj50FLHtlsoVfRfnHaZvyrooHcrlceNZdL/QBvJJVd9Ta55qCQK0gs4ss2oZDeV9zFCs6ewzYgVE5yfVmfFpVg==",
             "dependencies": {
+                "es-errors": "^1.3.0",
                 "function-bind": "^1.1.2",
-                "get-intrinsic": "^1.2.1",
-                "set-function-length": "^1.1.1"
+                "get-intrinsic": "^1.2.3",
+                "set-function-length": "^1.2.0"
+            },
+            "engines": {
+                "node": ">= 0.4"
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
@@ -1804,16 +1890,10 @@
             "dev": true
         },
         "node_modules/chokidar": {
-            "version": "3.5.3",
-            "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
-            "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+            "version": "3.6.0",
+            "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+            "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
             "dev": true,
-            "funding": [
-                {
-                    "type": "individual",
-                    "url": "https://paulmillr.com/funding/"
-                }
-            ],
             "dependencies": {
                 "anymatch": "~3.1.2",
                 "braces": "~3.0.2",
@@ -1826,6 +1906,9 @@
             "engines": {
                 "node": ">= 8.10.0"
             },
+            "funding": {
+                "url": "https://paulmillr.com/funding/"
+            },
             "optionalDependencies": {
                 "fsevents": "~2.3.2"
             }
@@ -2127,9 +2210,9 @@
             "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
         },
         "node_modules/core-js": {
-            "version": "3.35.0",
-            "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.35.0.tgz",
-            "integrity": "sha512-ntakECeqg81KqMueeGJ79Q5ZgQNR+6eaE8sxGCx62zMbAIj65q+uYvatToew3m6eAGdU4gNZwpZ34NMe4GYswg==",
+            "version": "3.35.1",
+            "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.35.1.tgz",
+            "integrity": "sha512-IgdsbxNyMskrTFxa9lWHyMwAJU5gXOPP+1yO+K59d50VLVAIDAbs7gIv705KzALModfK3ZrSZTPNpC0PQgIZuw==",
             "dev": true,
             "hasInstallScript": true,
             "funding": {
@@ -2243,13 +2326,14 @@
             }
         },
         "node_modules/define-data-property": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz",
-            "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==",
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.2.tgz",
+            "integrity": "sha512-SRtsSqsDbgpJBbW3pABMCOt6rQyeM8s8RiyeSN8jYG8sYmt/kGJejbydttUsnDs1tadr19tvhT4ShwMyoqAm4g==",
             "dependencies": {
-                "get-intrinsic": "^1.2.1",
+                "es-errors": "^1.3.0",
+                "get-intrinsic": "^1.2.2",
                 "gopd": "^1.0.1",
-                "has-property-descriptors": "^1.0.0"
+                "has-property-descriptors": "^1.0.1"
             },
             "engines": {
                 "node": ">= 0.4"
@@ -2321,9 +2405,9 @@
             "dev": true
         },
         "node_modules/dotenv": {
-            "version": "16.3.1",
-            "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz",
-            "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==",
+            "version": "16.4.1",
+            "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.1.tgz",
+            "integrity": "sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==",
             "engines": {
                 "node": ">=12"
             },
@@ -2355,16 +2439,16 @@
             }
         },
         "node_modules/dotenv-vault": {
-            "version": "1.25.0",
-            "resolved": "https://registry.npmjs.org/dotenv-vault/-/dotenv-vault-1.25.0.tgz",
-            "integrity": "sha512-+3isN+iq0E5VE+pfluBcNYb2qFf/Zu5q44Neh3Bazl82vk86xdUbI2z2cYHgJq5bMgRW1kUOaGWsgXjYlGUhng==",
+            "version": "1.26.0",
+            "resolved": "https://registry.npmjs.org/dotenv-vault/-/dotenv-vault-1.26.0.tgz",
+            "integrity": "sha512-2PNnlprtOdFEG9+hAAZxXegcjlJVZMSy88arnRR4YjwU/PwkDbdtk1uzw/D88D5EZ0b84n7YVQ6RccRXmW/Qzg==",
             "dev": true,
             "dependencies": {
                 "@oclif/core": "^1",
-                "@oclif/plugin-help": "^5.2.11",
-                "@oclif/plugin-not-found": "^2.3.24",
+                "@oclif/plugin-help": "^5.2.15",
+                "@oclif/plugin-not-found": "^2.3.34",
                 "@oclif/plugin-update": "^3.1.16",
-                "@oclif/plugin-warn-if-update-available": "^2.0.40",
+                "@oclif/plugin-warn-if-update-available": "^2.0.46",
                 "axios": "^0.27.2",
                 "chalk": "^4.1.2",
                 "dotenv": "^16.3.1"
@@ -2451,6 +2535,14 @@
                 "is-arrayish": "^0.2.1"
             }
         },
+        "node_modules/es-errors": {
+            "version": "1.3.0",
+            "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+            "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
         "node_modules/es6-promise": {
             "version": "3.3.1",
             "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz",
@@ -2458,9 +2550,9 @@
             "dev": true
         },
         "node_modules/escalade": {
-            "version": "3.1.1",
-            "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
-            "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+            "version": "3.1.2",
+            "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
+            "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
             "dev": true,
             "engines": {
                 "node": ">=6"
@@ -2690,6 +2782,15 @@
                 "node": ">= 0.6"
             }
         },
+        "node_modules/event-target-shim": {
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+            "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+            "dev": true,
+            "engines": {
+                "node": ">=6"
+            }
+        },
         "node_modules/eventemitter3": {
             "version": "4.0.7",
             "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
@@ -2854,9 +2955,9 @@
             }
         },
         "node_modules/fastq": {
-            "version": "1.16.0",
-            "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz",
-            "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==",
+            "version": "1.17.1",
+            "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
+            "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
             "dev": true,
             "dependencies": {
                 "reusify": "^1.0.4"
@@ -3147,15 +3248,19 @@
             }
         },
         "node_modules/get-intrinsic": {
-            "version": "1.2.2",
-            "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz",
-            "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==",
+            "version": "1.2.4",
+            "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+            "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
             "dependencies": {
+                "es-errors": "^1.3.0",
                 "function-bind": "^1.1.2",
                 "has-proto": "^1.0.1",
                 "has-symbols": "^1.0.3",
                 "hasown": "^2.0.0"
             },
+            "engines": {
+                "node": ">= 0.4"
+            },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
@@ -3467,9 +3572,9 @@
             ]
         },
         "node_modules/ignore": {
-            "version": "5.3.0",
-            "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
-            "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==",
+            "version": "5.3.1",
+            "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
+            "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
             "dev": true,
             "engines": {
                 "node": ">= 4"
@@ -4436,9 +4541,9 @@
             "dev": true
         },
         "node_modules/node": {
-            "version": "20.10.0",
-            "resolved": "https://registry.npmjs.org/node/-/node-20.10.0.tgz",
-            "integrity": "sha512-mIXfsYLNrafDq9es40WduIcwcGJLHVIa+itiKGcydM3qKx1HxymPWCKrG12PwG4oxsv4Jdke3uq2o4UiRgLYdQ==",
+            "version": "20.11.0",
+            "resolved": "https://registry.npmjs.org/node/-/node-20.11.0.tgz",
+            "integrity": "sha512-oY5yFtdoO73dhlfgEOcTtQAEoq6rMm2HcU9JDc9ZdnjRbkqkAZ/eaT4eZGIB1cCNOFx4OMpSTWD5k9vwta/EIQ==",
             "hasInstallScript": true,
             "dependencies": {
                 "node-bin-setup": "^1.0.0"
@@ -4592,9 +4697,9 @@
             }
         },
         "node_modules/npm": {
-            "version": "10.3.0",
-            "resolved": "https://registry.npmjs.org/npm/-/npm-10.3.0.tgz",
-            "integrity": "sha512-9u5GFc1UqI2DLlGI7QdjkpIaBs3UhTtY8KoCqYJK24gV/j/tByaI4BA4R7RkOc+ASqZMzFPKt4Pj2Z8JcGo//A==",
+            "version": "10.4.0",
+            "resolved": "https://registry.npmjs.org/npm/-/npm-10.4.0.tgz",
+            "integrity": "sha512-RS7Mx0OVfXlOcQLRePuDIYdFCVBPCNapWHplDK+mh7GDdP/Tvor4ocuybRRPSvfcRb2vjRJt1fHCqw3cr8qACQ==",
             "bundleDependencies": [
                 "@isaacs/string-locale-compare",
                 "@npmcli/arborist",
@@ -4658,7 +4763,6 @@
                 "semver",
                 "spdx-expression-parse",
                 "ssri",
-                "strip-ansi",
                 "supports-color",
                 "tar",
                 "text-table",
@@ -4677,8 +4781,8 @@
                 "@npmcli/map-workspaces": "^3.0.4",
                 "@npmcli/package-json": "^5.0.0",
                 "@npmcli/promise-spawn": "^7.0.1",
-                "@npmcli/run-script": "^7.0.3",
-                "@sigstore/tuf": "^2.2.0",
+                "@npmcli/run-script": "^7.0.4",
+                "@sigstore/tuf": "^2.3.0",
                 "abbrev": "^2.0.0",
                 "archy": "~1.0.0",
                 "cacache": "^18.0.2",
@@ -4724,7 +4828,7 @@
                 "npm-user-validate": "^2.0.0",
                 "npmlog": "^7.0.1",
                 "p-map": "^4.0.0",
-                "pacote": "^17.0.5",
+                "pacote": "^17.0.6",
                 "parse-conflict-json": "^3.0.1",
                 "proc-log": "^3.0.0",
                 "qrcode-terminal": "^0.12.0",
@@ -4732,7 +4836,6 @@
                 "semver": "^7.5.4",
                 "spdx-expression-parse": "^3.0.1",
                 "ssri": "^10.0.5",
-                "strip-ansi": "^7.1.0",
                 "supports-color": "^9.4.0",
                 "tar": "^6.2.0",
                 "text-table": "~0.2.0",
@@ -4777,6 +4880,18 @@
                 "node": ">=12"
             }
         },
+        "node_modules/npm/node_modules/@isaacs/cliui/node_modules/ansi-regex": {
+            "version": "6.0.1",
+            "dev": true,
+            "inBundle": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+            }
+        },
         "node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": {
             "version": "9.2.2",
             "dev": true,
@@ -4800,6 +4915,21 @@
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
+        "node_modules/npm/node_modules/@isaacs/cliui/node_modules/strip-ansi": {
+            "version": "7.1.0",
+            "dev": true,
+            "inBundle": true,
+            "license": "MIT",
+            "dependencies": {
+                "ansi-regex": "^6.0.1"
+            },
+            "engines": {
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+            }
+        },
         "node_modules/npm/node_modules/@isaacs/string-locale-compare": {
             "version": "1.1.0",
             "dev": true,
@@ -4823,7 +4953,7 @@
             }
         },
         "node_modules/npm/node_modules/@npmcli/arborist": {
-            "version": "7.3.0",
+            "version": "7.3.1",
             "dev": true,
             "inBundle": true,
             "license": "ISC",
@@ -4855,7 +4985,7 @@
                 "parse-conflict-json": "^3.0.0",
                 "proc-log": "^3.0.0",
                 "promise-all-reject-late": "^1.0.0",
-                "promise-call-limit": "^1.0.2",
+                "promise-call-limit": "^3.0.1",
                 "read-package-json-fast": "^3.0.2",
                 "semver": "^7.3.7",
                 "ssri": "^10.0.5",
@@ -5053,15 +5183,15 @@
             }
         },
         "node_modules/npm/node_modules/@npmcli/run-script": {
-            "version": "7.0.3",
+            "version": "7.0.4",
             "dev": true,
             "inBundle": true,
             "license": "ISC",
             "dependencies": {
                 "@npmcli/node-gyp": "^3.0.0",
+                "@npmcli/package-json": "^5.0.0",
                 "@npmcli/promise-spawn": "^7.0.0",
                 "node-gyp": "^10.0.0",
-                "read-package-json-fast": "^3.0.0",
                 "which": "^4.0.0"
             },
             "engines": {
@@ -5079,7 +5209,7 @@
             }
         },
         "node_modules/npm/node_modules/@sigstore/bundle": {
-            "version": "2.1.0",
+            "version": "2.1.1",
             "dev": true,
             "inBundle": true,
             "license": "Apache-2.0",
@@ -5090,6 +5220,15 @@
                 "node": "^16.14.0 || >=18.0.0"
             }
         },
+        "node_modules/npm/node_modules/@sigstore/core": {
+            "version": "0.2.0",
+            "dev": true,
+            "inBundle": true,
+            "license": "Apache-2.0",
+            "engines": {
+                "node": "^16.14.0 || >=18.0.0"
+            }
+        },
         "node_modules/npm/node_modules/@sigstore/protobuf-specs": {
             "version": "0.2.1",
             "dev": true,
@@ -5100,12 +5239,13 @@
             }
         },
         "node_modules/npm/node_modules/@sigstore/sign": {
-            "version": "2.2.0",
+            "version": "2.2.1",
             "dev": true,
             "inBundle": true,
             "license": "Apache-2.0",
             "dependencies": {
-                "@sigstore/bundle": "^2.1.0",
+                "@sigstore/bundle": "^2.1.1",
+                "@sigstore/core": "^0.2.0",
                 "@sigstore/protobuf-specs": "^0.2.1",
                 "make-fetch-happen": "^13.0.0"
             },
@@ -5114,13 +5254,27 @@
             }
         },
         "node_modules/npm/node_modules/@sigstore/tuf": {
-            "version": "2.2.0",
+            "version": "2.3.0",
             "dev": true,
             "inBundle": true,
             "license": "Apache-2.0",
             "dependencies": {
                 "@sigstore/protobuf-specs": "^0.2.1",
-                "tuf-js": "^2.1.0"
+                "tuf-js": "^2.2.0"
+            },
+            "engines": {
+                "node": "^16.14.0 || >=18.0.0"
+            }
+        },
+        "node_modules/npm/node_modules/@sigstore/verify": {
+            "version": "0.1.0",
+            "dev": true,
+            "inBundle": true,
+            "license": "Apache-2.0",
+            "dependencies": {
+                "@sigstore/bundle": "^2.1.1",
+                "@sigstore/core": "^0.2.0",
+                "@sigstore/protobuf-specs": "^0.2.1"
             },
             "engines": {
                 "node": "^16.14.0 || >=18.0.0"
@@ -5183,15 +5337,12 @@
             }
         },
         "node_modules/npm/node_modules/ansi-regex": {
-            "version": "6.0.1",
+            "version": "5.0.1",
             "dev": true,
             "inBundle": true,
             "license": "MIT",
             "engines": {
-                "node": ">=12"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+                "node": ">=8"
             }
         },
         "node_modules/npm/node_modules/ansi-styles": {
@@ -5368,27 +5519,6 @@
                 "node": ">= 10"
             }
         },
-        "node_modules/npm/node_modules/cli-columns/node_modules/ansi-regex": {
-            "version": "5.0.1",
-            "dev": true,
-            "inBundle": true,
-            "license": "MIT",
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/npm/node_modules/cli-columns/node_modules/strip-ansi": {
-            "version": "6.0.1",
-            "dev": true,
-            "inBundle": true,
-            "license": "MIT",
-            "dependencies": {
-                "ansi-regex": "^5.0.1"
-            },
-            "engines": {
-                "node": ">=8"
-            }
-        },
         "node_modules/npm/node_modules/cli-table3": {
             "version": "0.6.3",
             "dev": true,
@@ -5462,27 +5592,6 @@
                 "node": ">=8.0.0"
             }
         },
-        "node_modules/npm/node_modules/columnify/node_modules/ansi-regex": {
-            "version": "5.0.1",
-            "dev": true,
-            "inBundle": true,
-            "license": "MIT",
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/npm/node_modules/columnify/node_modules/strip-ansi": {
-            "version": "6.0.1",
-            "dev": true,
-            "inBundle": true,
-            "license": "MIT",
-            "dependencies": {
-                "ansi-regex": "^5.0.1"
-            },
-            "engines": {
-                "node": ">=8"
-            }
-        },
         "node_modules/npm/node_modules/common-ancestor-path": {
             "version": "1.0.1",
             "dev": true,
@@ -5688,27 +5797,6 @@
                 "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
             }
         },
-        "node_modules/npm/node_modules/gauge/node_modules/ansi-regex": {
-            "version": "5.0.1",
-            "dev": true,
-            "inBundle": true,
-            "license": "MIT",
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/npm/node_modules/gauge/node_modules/strip-ansi": {
-            "version": "6.0.1",
-            "dev": true,
-            "inBundle": true,
-            "license": "MIT",
-            "dependencies": {
-                "ansi-regex": "^5.0.1"
-            },
-            "engines": {
-                "node": ">=8"
-            }
-        },
         "node_modules/npm/node_modules/glob": {
             "version": "10.3.10",
             "dev": true,
@@ -6003,7 +6091,7 @@
             }
         },
         "node_modules/npm/node_modules/libnpmdiff": {
-            "version": "6.0.5",
+            "version": "6.0.6",
             "dev": true,
             "inBundle": true,
             "license": "ISC",
@@ -6023,7 +6111,7 @@
             }
         },
         "node_modules/npm/node_modules/libnpmexec": {
-            "version": "7.0.6",
+            "version": "7.0.7",
             "dev": true,
             "inBundle": true,
             "license": "ISC",
@@ -6045,7 +6133,7 @@
             }
         },
         "node_modules/npm/node_modules/libnpmfund": {
-            "version": "5.0.3",
+            "version": "5.0.4",
             "dev": true,
             "inBundle": true,
             "license": "ISC",
@@ -6083,7 +6171,7 @@
             }
         },
         "node_modules/npm/node_modules/libnpmpack": {
-            "version": "6.0.5",
+            "version": "6.0.6",
             "dev": true,
             "inBundle": true,
             "license": "ISC",
@@ -6098,7 +6186,7 @@
             }
         },
         "node_modules/npm/node_modules/libnpmpublish": {
-            "version": "9.0.3",
+            "version": "9.0.4",
             "dev": true,
             "inBundle": true,
             "license": "ISC",
@@ -6109,7 +6197,7 @@
                 "npm-registry-fetch": "^16.0.0",
                 "proc-log": "^3.0.0",
                 "semver": "^7.3.7",
-                "sigstore": "^2.1.0",
+                "sigstore": "^2.2.0",
                 "ssri": "^10.0.5"
             },
             "engines": {
@@ -6605,7 +6693,7 @@
             }
         },
         "node_modules/npm/node_modules/pacote": {
-            "version": "17.0.5",
+            "version": "17.0.6",
             "dev": true,
             "inBundle": true,
             "license": "ISC",
@@ -6625,7 +6713,7 @@
                 "promise-retry": "^2.0.1",
                 "read-package-json": "^7.0.0",
                 "read-package-json-fast": "^3.0.0",
-                "sigstore": "^2.0.0",
+                "sigstore": "^2.2.0",
                 "ssri": "^10.0.0",
                 "tar": "^6.1.11"
             },
@@ -6707,7 +6795,7 @@
             }
         },
         "node_modules/npm/node_modules/promise-call-limit": {
-            "version": "1.0.2",
+            "version": "3.0.1",
             "dev": true,
             "inBundle": true,
             "license": "ISC",
@@ -6886,15 +6974,17 @@
             }
         },
         "node_modules/npm/node_modules/sigstore": {
-            "version": "2.1.0",
+            "version": "2.2.0",
             "dev": true,
             "inBundle": true,
             "license": "Apache-2.0",
             "dependencies": {
-                "@sigstore/bundle": "^2.1.0",
+                "@sigstore/bundle": "^2.1.1",
+                "@sigstore/core": "^0.2.0",
                 "@sigstore/protobuf-specs": "^0.2.1",
-                "@sigstore/sign": "^2.1.0",
-                "@sigstore/tuf": "^2.1.0"
+                "@sigstore/sign": "^2.2.1",
+                "@sigstore/tuf": "^2.3.0",
+                "@sigstore/verify": "^0.1.0"
             },
             "engines": {
                 "node": "^16.14.0 || >=18.0.0"
@@ -7011,37 +7101,7 @@
                 "node": ">=8"
             }
         },
-        "node_modules/npm/node_modules/string-width-cjs/node_modules/ansi-regex": {
-            "version": "5.0.1",
-            "dev": true,
-            "inBundle": true,
-            "license": "MIT",
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/npm/node_modules/string-width-cjs/node_modules/strip-ansi": {
-            "version": "6.0.1",
-            "dev": true,
-            "inBundle": true,
-            "license": "MIT",
-            "dependencies": {
-                "ansi-regex": "^5.0.1"
-            },
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/npm/node_modules/string-width/node_modules/ansi-regex": {
-            "version": "5.0.1",
-            "dev": true,
-            "inBundle": true,
-            "license": "MIT",
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/npm/node_modules/string-width/node_modules/strip-ansi": {
+        "node_modules/npm/node_modules/strip-ansi": {
             "version": "6.0.1",
             "dev": true,
             "inBundle": true,
@@ -7053,21 +7113,6 @@
                 "node": ">=8"
             }
         },
-        "node_modules/npm/node_modules/strip-ansi": {
-            "version": "7.1.0",
-            "dev": true,
-            "inBundle": true,
-            "license": "MIT",
-            "dependencies": {
-                "ansi-regex": "^6.0.1"
-            },
-            "engines": {
-                "node": ">=12"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/strip-ansi?sponsor=1"
-            }
-        },
         "node_modules/npm/node_modules/strip-ansi-cjs": {
             "name": "strip-ansi",
             "version": "6.0.1",
@@ -7081,15 +7126,6 @@
                 "node": ">=8"
             }
         },
-        "node_modules/npm/node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
-            "version": "5.0.1",
-            "dev": true,
-            "inBundle": true,
-            "license": "MIT",
-            "engines": {
-                "node": ">=8"
-            }
-        },
         "node_modules/npm/node_modules/supports-color": {
             "version": "9.4.0",
             "dev": true,
@@ -7174,7 +7210,7 @@
             }
         },
         "node_modules/npm/node_modules/tuf-js": {
-            "version": "2.1.0",
+            "version": "2.2.0",
             "dev": true,
             "inBundle": true,
             "license": "MIT",
@@ -7322,15 +7358,6 @@
                 "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
             }
         },
-        "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
-            "version": "5.0.1",
-            "dev": true,
-            "inBundle": true,
-            "license": "MIT",
-            "engines": {
-                "node": ">=8"
-            }
-        },
         "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
             "version": "4.3.0",
             "dev": true,
@@ -7346,16 +7373,16 @@
                 "url": "https://github.com/chalk/ansi-styles?sponsor=1"
             }
         },
-        "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
+        "node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": {
             "version": "6.0.1",
             "dev": true,
             "inBundle": true,
             "license": "MIT",
-            "dependencies": {
-                "ansi-regex": "^5.0.1"
-            },
             "engines": {
-                "node": ">=8"
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/ansi-regex?sponsor=1"
             }
         },
         "node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": {
@@ -7381,6 +7408,21 @@
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
+        "node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": {
+            "version": "7.1.0",
+            "dev": true,
+            "inBundle": true,
+            "license": "MIT",
+            "dependencies": {
+                "ansi-regex": "^6.0.1"
+            },
+            "engines": {
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+            }
+        },
         "node_modules/npm/node_modules/write-file-atomic": {
             "version": "5.0.1",
             "dev": true,
@@ -7787,6 +7829,17 @@
                 "url": "https://github.com/sponsors/jonschlinkert"
             }
         },
+        "node_modules/picomatch-browser": {
+            "version": "2.2.6",
+            "resolved": "https://registry.npmjs.org/picomatch-browser/-/picomatch-browser-2.2.6.tgz",
+            "integrity": "sha512-0ypsOQt9D4e3hziV8O4elD9uN0z/jtUEfxVRtNaAAtXIyUx9m/SzlO020i8YNL2aL/E6blOvvHQcin6HZlFy/w==",
+            "engines": {
+                "node": ">=8.6"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/jonschlinkert"
+            }
+        },
         "node_modules/pluralize": {
             "version": "8.0.0",
             "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz",
@@ -7797,9 +7850,9 @@
             }
         },
         "node_modules/polished": {
-            "version": "4.2.2",
-            "resolved": "https://registry.npmjs.org/polished/-/polished-4.2.2.tgz",
-            "integrity": "sha512-Sz2Lkdxz6F2Pgnpi9U5Ng/WdWAUZxmHrNPoVlm3aAemxoy2Qy7LGjQg4uf8qKelDAUW94F4np3iH2YPf2qefcQ==",
+            "version": "4.3.1",
+            "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz",
+            "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==",
             "dev": true,
             "dependencies": {
                 "@babel/runtime": "^7.17.8"
@@ -7853,13 +7906,13 @@
             }
         },
         "node_modules/prisma": {
-            "version": "5.8.1",
-            "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.8.1.tgz",
-            "integrity": "sha512-N6CpjzECnUHZ5beeYpDzkt2rYpEdAeqXX2dweu6BoQaeYkNZrC/WJHM+5MO/uidFHTak8QhkPKBWck1o/4MD4A==",
+            "version": "5.9.1",
+            "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.9.1.tgz",
+            "integrity": "sha512-Hy/8KJZz0ELtkw4FnG9MS9rNWlXcJhf98Z2QMqi0QiVMoS8PzsBkpla0/Y5hTlob8F3HeECYphBjqmBxrluUrQ==",
             "devOptional": true,
             "hasInstallScript": true,
             "dependencies": {
-                "@prisma/engines": "5.8.1"
+                "@prisma/engines": "5.9.1"
             },
             "bin": {
                 "prisma": "build/index.js"
@@ -7991,6 +8044,11 @@
                 "node": ">= 0.6"
             }
         },
+        "node_modules/rate-limiter-flexible": {
+            "version": "4.0.1",
+            "resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-4.0.1.tgz",
+            "integrity": "sha512-2/dGHpDFpeA0+755oUkW+EKyklqLS9lu0go9pDsbhqQjZcxfRyJ6LA4JI0+HAdZ2bemD/oOjUeZQB2lCZqXQfQ=="
+        },
         "node_modules/raw-body": {
             "version": "2.5.1",
             "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
@@ -8283,9 +8341,9 @@
             }
         },
         "node_modules/semver": {
-            "version": "7.5.4",
-            "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
-            "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+            "version": "7.6.0",
+            "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
+            "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
             "dependencies": {
                 "lru-cache": "^6.0.0"
             },
@@ -8352,13 +8410,14 @@
             }
         },
         "node_modules/set-function-length": {
-            "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz",
-            "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==",
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz",
+            "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==",
             "dependencies": {
-                "define-data-property": "^1.1.1",
+                "define-data-property": "^1.1.2",
+                "es-errors": "^1.3.0",
                 "function-bind": "^1.1.2",
-                "get-intrinsic": "^1.2.2",
+                "get-intrinsic": "^1.2.3",
                 "gopd": "^1.0.1",
                 "has-property-descriptors": "^1.0.1"
             },
@@ -8453,13 +8512,17 @@
             "dev": true
         },
         "node_modules/side-channel": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
-            "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+            "version": "1.0.5",
+            "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz",
+            "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==",
             "dependencies": {
-                "call-bind": "^1.0.0",
-                "get-intrinsic": "^1.0.2",
-                "object-inspect": "^1.9.0"
+                "call-bind": "^1.0.6",
+                "es-errors": "^1.3.0",
+                "get-intrinsic": "^1.2.4",
+                "object-inspect": "^1.13.1"
+            },
+            "engines": {
+                "node": ">= 0.4"
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
@@ -8635,12 +8698,15 @@
             }
         },
         "node_modules/streamx": {
-            "version": "2.15.6",
-            "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.6.tgz",
-            "integrity": "sha512-q+vQL4AAz+FdfT137VF69Cc/APqUbxy+MDOImRrMvchJpigHj9GksgDU2LYbO9rx7RX6osWgxJB2WxhYv4SZAw==",
+            "version": "2.15.8",
+            "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.8.tgz",
+            "integrity": "sha512-6pwMeMY/SuISiRsuS8TeIrAzyFbG5gGPHFQsYjUr/pbBadaL1PCWmzKw+CHZSwainfvcF6Si6cVLq4XTEwswFQ==",
             "dependencies": {
                 "fast-fifo": "^1.1.0",
                 "queue-tick": "^1.0.1"
+            },
+            "optionalDependencies": {
+                "bare-events": "^2.2.0"
             }
         },
         "node_modules/string_decoder": {
@@ -8771,9 +8837,9 @@
             }
         },
         "node_modules/swagger-ui-dist": {
-            "version": "5.11.0",
-            "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.11.0.tgz",
-            "integrity": "sha512-j0PIATqQSEFGOLmiJOJZj1X1Jt6bFIur3JpY7+ghliUnfZs0fpWDdHEkn9q7QUlBtKbkn6TepvSxTqnE8l3s0A=="
+            "version": "5.11.3",
+            "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.11.3.tgz",
+            "integrity": "sha512-vQ+Pe73xt7vMVbX40L6nHu4sDmNCM6A+eMVJPGvKrifHQ4LO3smH0jCiiefKzsVl7OlOcVEnrZ9IFzYwElfMkA=="
         },
         "node_modules/swagger-ui-express": {
             "version": "5.0.0",
@@ -8859,9 +8925,9 @@
             }
         },
         "node_modules/tar-stream": {
-            "version": "3.1.6",
-            "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz",
-            "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==",
+            "version": "3.1.7",
+            "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz",
+            "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==",
             "dependencies": {
                 "b4a": "^1.6.4",
                 "fast-fifo": "^1.2.0",
@@ -8945,12 +9011,12 @@
             }
         },
         "node_modules/ts-api-utils": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz",
-            "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==",
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz",
+            "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==",
             "dev": true,
             "engines": {
-                "node": ">=16.13.0"
+                "node": ">=16"
             },
             "peerDependencies": {
                 "typescript": ">=4.2.0"
@@ -9250,9 +9316,9 @@
             }
         },
         "node_modules/winston-transport": {
-            "version": "4.6.0",
-            "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz",
-            "integrity": "sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==",
+            "version": "4.7.0",
+            "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz",
+            "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==",
             "dependencies": {
                 "logform": "^2.3.2",
                 "readable-stream": "^3.6.0",
@@ -9338,6 +9404,11 @@
                 }
             }
         },
+        "node_modules/xcase": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/xcase/-/xcase-2.0.1.tgz",
+            "integrity": "sha512-UmFXIPU+9Eg3E9m/728Bii0lAIuoc+6nbrNUKaRPJOFp91ih44qqGlWtxMB6kXFrRD6po+86ksHM5XHCfk6iPw=="
+        },
         "node_modules/xtend": {
             "version": "4.0.2",
             "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
diff --git a/ExpressAPI/package.json b/ExpressAPI/package.json
index bce35f7bb2f86ab0ca46423c6f07dcc939c0dfaa..4d1a54382c5c9625e7bcdbbf88b2cbb26b0e545d 100644
--- a/ExpressAPI/package.json
+++ b/ExpressAPI/package.json
@@ -1,7 +1,7 @@
 {
     "name"           : "dojo_backend_api",
     "description"    : "Backend API of the Dojo project",
-    "version"        : "3.4.2",
+    "version"        : "3.5.0",
     "license"        : "AGPLv3",
     "author"         : "Michaël Minelli <dojo@minelli.me>",
     "main"           : "dist/src/app.js",
@@ -28,11 +28,12 @@
         "seed": "node dist/prisma/seed"
     },
     "dependencies"   : {
-        "@prisma/client"      : "^5.8.1",
-        "axios"               : "^1.6.5",
+        "@gitbeaker/rest"     : "^39.34.2",
+        "@prisma/client"      : "^5.9.1",
+        "axios"               : "^1.6.7",
         "compression"         : "^1.7.4",
         "cors"                : "^2.8.5",
-        "dotenv"              : "^16.3.1",
+        "dotenv"              : "^16.4.1",
         "dotenv-expand"       : "^10.0.0",
         "express"             : "^4.18.2",
         "express-validator"   : "^7.0.1",
@@ -44,38 +45,38 @@
         "morgan"              : "^1.10.0",
         "multer"              : "^1.4.5-lts.1",
         "mysql"               : "^2.18.1",
-        "node"                : "^20.10.0",
+        "node"                : "^20.11.0",
         "parse-link-header"   : "^2.0.0",
-        "semver"              : "^7.5.4",
+        "semver"              : "^7.6.0",
         "swagger-ui-express"  : "^5.0.0",
-        "tar-stream"          : "^3.1.6",
+        "tar-stream"          : "^3.1.7",
         "uuid"                : "^9.0.1",
         "winston"             : "^3.11.0",
         "zod"                 : "^3.22.4",
         "zod-validation-error": "^3.0.0"
     },
     "devDependencies": {
-        "@redocly/cli"                    : "^1.6.0",
+        "@redocly/cli"                    : "^1.8.2",
         "@types/compression"              : "^1.7.5",
         "@types/cors"                     : "^2.8.17",
         "@types/express"                  : "^4.17.21",
         "@types/jsonwebtoken"             : "^9.0.5",
         "@types/morgan"                   : "^1.9.9",
         "@types/multer"                   : "^1.4.11",
-        "@types/node"                     : "^20.11.5",
+        "@types/node"                     : "^20.11.17",
         "@types/parse-link-header"        : "^2.0.3",
         "@types/semver"                   : "^7.5.6",
         "@types/swagger-ui-express"       : "^4.1.6",
         "@types/tar-stream"               : "^3.1.3",
-        "@types/uuid"                     : "^9.0.7",
-        "@typescript-eslint/eslint-plugin": "^6.18.1",
-        "@typescript-eslint/parser"       : "^6.18.1",
+        "@types/uuid"                     : "^9.0.8",
+        "@typescript-eslint/eslint-plugin": "^6.21.0",
+        "@typescript-eslint/parser"       : "^6.21.0",
         "dotenv-cli"                      : "^7.3.0",
-        "dotenv-vault"                    : "^1.25.0",
+        "dotenv-vault"                    : "^1.26.0",
         "genversion"                      : "^3.2.0",
         "nodemon"                         : "^3.0.3",
-        "npm"                             : "^10.3.0",
-        "prisma"                          : "^5.8.1",
+        "npm"                             : "^10.4.0",
+        "prisma"                          : "^5.9.1",
         "ts-node"                         : "^10.9.2",
         "typescript"                      : "^5.3.3"
     }
diff --git a/ExpressAPI/prisma/migrations/20240208132018_add_correction_to_assignment/migration.sql b/ExpressAPI/prisma/migrations/20240208132018_add_correction_to_assignment/migration.sql
new file mode 100644
index 0000000000000000000000000000000000000000..cf8fa0240acfd338b0414f0394685a96b8b2602b
--- /dev/null
+++ b/ExpressAPI/prisma/migrations/20240208132018_add_correction_to_assignment/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE `Exercise` ADD COLUMN `correctionCommit` JSON NULL;
diff --git a/ExpressAPI/prisma/schema.prisma b/ExpressAPI/prisma/schema.prisma
index a68226e0868e475d54557f330fa35699e2f34bf7..f60367392fbfdcdf104a78dea1e20a0101bdddb9 100644
--- a/ExpressAPI/prisma/schema.prisma
+++ b/ExpressAPI/prisma/schema.prisma
@@ -50,6 +50,8 @@ model Exercise {
     gitlabLastInfo     Json     @db.Json
     gitlabLastInfoDate DateTime
 
+    correctionCommit Json? @db.Json
+
     assignment Assignment @relation(fields: [assignmentName], references: [name], onDelete: NoAction, onUpdate: Cascade)
 
     members User[]
diff --git a/ExpressAPI/src/helpers/DatabaseHelper.ts b/ExpressAPI/src/helpers/DatabaseHelper.ts
index 89ec9c767cb8f879011a7f5e547eb1942657de7b..9dc14bb292ef7e2921617c135b1e4f8d014e2a78 100644
--- a/ExpressAPI/src/helpers/DatabaseHelper.ts
+++ b/ExpressAPI/src/helpers/DatabaseHelper.ts
@@ -1,7 +1,9 @@
-import { PrismaClient }    from '@prisma/client';
-import logger              from '../shared/logging/WinstonLogger';
-import UserQueryExtension  from './Prisma/Extensions/UserQueryExtension';
-import UserResultExtension from './Prisma/Extensions/UserResultExtension';
+import { PrismaClient }          from '@prisma/client';
+import logger                    from '../shared/logging/WinstonLogger';
+import UserQueryExtension        from './Prisma/Extensions/UserQueryExtension';
+import UserResultExtension       from './Prisma/Extensions/UserResultExtension';
+import AssignmentResultExtension from './Prisma/Extensions/AssignmentResultExtension';
+import ExerciseResultExtension   from './Prisma/Extensions/ExerciseResultExtension';
 
 
 const prisma = new PrismaClient({
@@ -29,7 +31,7 @@ prisma.$on('warn', e => logger.warn(`Prisma => ${ e.message }`));
 prisma.$on('error', e => logger.error(`Prisma => ${ e.message }`));
 
 
-const db = prisma.$extends(UserQueryExtension).$extends(UserResultExtension);
+const db = prisma.$extends(UserQueryExtension).$extends(UserResultExtension).$extends(AssignmentResultExtension).$extends(ExerciseResultExtension);
 
 
 export default db;
\ No newline at end of file
diff --git a/ExpressAPI/src/helpers/DojoModelsHelper.ts b/ExpressAPI/src/helpers/DojoModelsHelper.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8fa9e5f2d28180bdf5711fb65f572218e253160b
--- /dev/null
+++ b/ExpressAPI/src/helpers/DojoModelsHelper.ts
@@ -0,0 +1,33 @@
+import LazyVal from '../shared/helpers/LazyVal';
+
+
+class DojoModelsHelper {
+    /**
+     * Get a full serializable object from a given object that contains LazyVal instances
+     *
+     * @param obj
+     * @param depth The depth of the search for LazyVal instances
+     */
+    async getFullSerializableObject<T extends NonNullable<unknown>>(obj: T, depth: number = 0): Promise<unknown> {
+        /* eslint-disable-next-line  @typescript-eslint/no-explicit-any */
+        const result: any = {};
+
+        for ( const key in obj ) {
+            let value: unknown = obj[key];
+            if ( value instanceof LazyVal ) {
+                value = await (obj[key] as LazyVal<unknown>).value;
+            }
+
+            if ( typeof value === 'object' && obj[key] !== null && depth > 0 ) {
+                result[key] = await this.getFullSerializableObject(value as NonNullable<unknown>, depth - 1);
+            } else {
+                result[key] = value;
+            }
+        }
+
+        return result;
+    }
+}
+
+
+export default new DojoModelsHelper();
\ No newline at end of file
diff --git a/ExpressAPI/src/helpers/DojoValidators.ts b/ExpressAPI/src/helpers/DojoValidators.ts
index 98a28252c6bca786fe23ad6b08e56db54c33aca0..38465417c46274cff0e46ee3dbdc2929cb17f05b 100644
--- a/ExpressAPI/src/helpers/DojoValidators.ts
+++ b/ExpressAPI/src/helpers/DojoValidators.ts
@@ -7,6 +7,8 @@ import express                                                      from 'expres
 import logger                                                       from '../shared/logging/WinstonLogger';
 import Json5FileValidator                                           from '../shared/helpers/Json5FileValidator';
 import ExerciseResultsFile                                          from '../shared/types/Dojo/ExerciseResultsFile';
+import ParamsCallbackManager                                        from '../middlewares/ParamsCallbackManager';
+import ExerciseManager                                              from '../managers/ExerciseManager';
 
 
 declare type DojoMeta = Meta & {
@@ -106,6 +108,32 @@ class DojoValidators {
                                                                               });
                                                                           }
                                                                       });
+
+    readonly exerciseIdOrUrlValidator = this.toValidatorSchemaOptions({
+                                                                          bail        : true,
+                                                                          errorMessage: 'ExerciseIdOrUrl: not provided or invalid',
+                                                                          options     : (_value, {
+                                                                              req,
+                                                                              path
+                                                                          }) => {
+                                                                              return new Promise((resolve, reject) => {
+                                                                                  const exerciseIdOrUrl = this.getParamValue(req, path) as string;
+                                                                                  if ( exerciseIdOrUrl ) {
+                                                                                      ParamsCallbackManager.initBoundParams(req);
+
+                                                                                      ExerciseManager.get(exerciseIdOrUrl).then((exercise) => {
+                                                                                          req.boundParams.exercise = exercise;
+
+                                                                                          exercise !== undefined ? resolve(true) : reject();
+                                                                                      }).catch(() => {
+                                                                                          reject();
+                                                                                      });
+                                                                                  } else {
+                                                                                      reject();
+                                                                                  }
+                                                                              });
+                                                                          }
+                                                                      });
 }
 
 
diff --git a/ExpressAPI/src/helpers/Prisma/Extensions/AssignmentResultExtension.ts b/ExpressAPI/src/helpers/Prisma/Extensions/AssignmentResultExtension.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a5f813993c56c3d5c4824854231a2a6486cddd3b
--- /dev/null
+++ b/ExpressAPI/src/helpers/Prisma/Extensions/AssignmentResultExtension.ts
@@ -0,0 +1,41 @@
+import { Prisma }   from '@prisma/client';
+import { Exercise } from '../../../types/DatabaseTypes';
+import db           from '../../DatabaseHelper';
+import LazyVal      from '../../../shared/helpers/LazyVal';
+
+
+async function getCorrections(assignment: { name: string }): Promise<Array<Partial<Exercise>> | undefined> {
+    try {
+        return await db.exercise.findMany({
+                                              where  : {
+                                                  assignmentName  : assignment.name,
+                                                  correctionCommit: {
+                                                      not: Prisma.JsonNull
+                                                  }
+                                              },
+                                              include: {
+                                                  assignment: false,
+                                                  members   : true,
+                                                  results   : false
+                                              }
+                                          }) as Array<Partial<Exercise>> ?? undefined;
+    } catch ( e ) {
+        return undefined;
+    }
+}
+
+export default Prisma.defineExtension(client => {
+    return client.$extends({
+                               result: {
+                                   assignment: {
+                                       corrections: {
+                                           compute(assignment) {
+                                               return new LazyVal<Array<Partial<Exercise>> | undefined>(() => {
+                                                   return getCorrections(assignment);
+                                               });
+                                           }
+                                       }
+                                   }
+                               }
+                           });
+});
\ No newline at end of file
diff --git a/ExpressAPI/src/helpers/Prisma/Extensions/ExerciseResultExtension.ts b/ExpressAPI/src/helpers/Prisma/Extensions/ExerciseResultExtension.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e11b4e247e78b59b49e0ebd52cb669857954d431
--- /dev/null
+++ b/ExpressAPI/src/helpers/Prisma/Extensions/ExerciseResultExtension.ts
@@ -0,0 +1,19 @@
+import { Prisma } from '@prisma/client';
+
+
+export default Prisma.defineExtension(client => {
+    return client.$extends({
+                               result: {
+                                   exercise: {
+                                       isCorrection: {
+                                           needs: {
+                                               correctionCommit: true
+                                           },
+                                           compute(exercise) {
+                                               return exercise.correctionCommit != null;
+                                           }
+                                       }
+                                   }
+                               }
+                           });
+});
\ No newline at end of file
diff --git a/ExpressAPI/src/managers/ExerciseManager.ts b/ExpressAPI/src/managers/ExerciseManager.ts
index 66cfda8a89bb8f8d726f03c54a2bdcf915b45914..720827d904b1332b90b632aa2ca965b23586b45f 100644
--- a/ExpressAPI/src/managers/ExerciseManager.ts
+++ b/ExpressAPI/src/managers/ExerciseManager.ts
@@ -4,7 +4,9 @@ import db           from '../helpers/DatabaseHelper';
 
 
 class ExerciseManager {
-    async get(id: string, include: Prisma.ExerciseInclude | undefined = undefined): Promise<Exercise | undefined> {
+    async get(idOrUrl: string, include: Prisma.ExerciseInclude | undefined = undefined): Promise<Exercise | undefined> {
+        const id = idOrUrl.replace('.git', '').split('_').pop()!;
+
         return await db.exercise.findUnique({
                                                 where  : {
                                                     id: id
diff --git a/ExpressAPI/src/managers/GitlabManager.ts b/ExpressAPI/src/managers/GitlabManager.ts
index 390fba57640e11b4514caa37df8131a4b9622886..3455f8b7accad04dc7c09ace93b1c297cb633d49 100644
--- a/ExpressAPI/src/managers/GitlabManager.ts
+++ b/ExpressAPI/src/managers/GitlabManager.ts
@@ -1,22 +1,29 @@
-import axios             from 'axios';
-import Config            from '../config/Config';
-import GitlabRepository  from '../shared/types/Gitlab/GitlabRepository';
-import GitlabAccessLevel from '../shared/types/Gitlab/GitlabAccessLevel';
-import GitlabMember      from '../shared/types/Gitlab/GitlabMember';
-import { StatusCodes }   from 'http-status-codes';
-import GitlabVisibility  from '../shared/types/Gitlab/GitlabVisibility';
-import GitlabUser        from '../shared/types/Gitlab/GitlabUser';
-import GitlabTreeFile    from '../shared/types/Gitlab/GitlabTreeFile';
-import parseLinkHeader   from 'parse-link-header';
-import GitlabFile        from '../shared/types/Gitlab/GitlabFile';
-import express           from 'express';
-import GitlabRoute       from '../shared/types/Gitlab/GitlabRoute';
-import SharedConfig      from '../shared/config/SharedConfig';
-import GitlabProfile     from '../shared/types/Gitlab/GitlabProfile';
-import GitlabRelease     from '../shared/types/Gitlab/GitlabRelease';
+import axios                    from 'axios';
+import Config                   from '../config/Config';
+import GitlabRepository         from '../shared/types/Gitlab/GitlabRepository';
+import GitlabAccessLevel        from '../shared/types/Gitlab/GitlabAccessLevel';
+import GitlabMember             from '../shared/types/Gitlab/GitlabMember';
+import { StatusCodes }          from 'http-status-codes';
+import GitlabVisibility         from '../shared/types/Gitlab/GitlabVisibility';
+import GitlabUser               from '../shared/types/Gitlab/GitlabUser';
+import GitlabTreeFile           from '../shared/types/Gitlab/GitlabTreeFile';
+import parseLinkHeader          from 'parse-link-header';
+import GitlabFile               from '../shared/types/Gitlab/GitlabFile';
+import express                  from 'express';
+import GitlabRoute              from '../shared/types/Gitlab/GitlabRoute';
+import SharedConfig             from '../shared/config/SharedConfig';
+import GitlabProfile            from '../shared/types/Gitlab/GitlabProfile';
+import GitlabRelease            from '../shared/types/Gitlab/GitlabRelease';
+import { CommitSchema, Gitlab } from '@gitbeaker/rest';
+import logger                   from '../shared/logging/WinstonLogger';
 
 
 class GitlabManager {
+    readonly api = new Gitlab({
+                                  host : SharedConfig.gitlab.URL,
+                                  token: Config.gitlab.account.token
+                              });
+
     private getApiUrl(route: GitlabRoute): string {
         return `${ SharedConfig.gitlab.apiURL }${ route }`;
     }
@@ -75,6 +82,21 @@ class GitlabManager {
         return response.data;
     }
 
+    async getRepositoryLastCommit(repoId: number, branch: string = 'main'): Promise<CommitSchema | undefined> {
+        try {
+            const commits = await this.api.Commits.all(repoId, {
+                refName : branch,
+                maxPages: 1,
+                perPage : 1
+            });
+
+            return commits.length > 0 ? commits[0] : undefined;
+        } catch ( e ) {
+            logger.error(e);
+            return undefined;
+        }
+    }
+
     async createRepository(name: string, description: string, visibility: string, initializeWithReadme: boolean, namespace: number, sharedRunnersEnabled: boolean, wikiEnabled: boolean, import_url: string): Promise<GitlabRepository> {
         const response = await axios.post<GitlabRepository>(this.getApiUrl(GitlabRoute.REPOSITORY_CREATE), {
             name                  : name,
diff --git a/ExpressAPI/src/middlewares/ParamsCallbackManager.ts b/ExpressAPI/src/middlewares/ParamsCallbackManager.ts
index cfcb275a4c3239e33f83fbb6360a10e31b5b0141..6dd5303a36e38091833b733472c0227733788ebe 100644
--- a/ExpressAPI/src/middlewares/ParamsCallbackManager.ts
+++ b/ExpressAPI/src/middlewares/ParamsCallbackManager.ts
@@ -39,7 +39,7 @@ class ParamsCallbackManager {
             staff    : true
         } ], 'assignment');
 
-        this.listenParam('exerciseId', backend, (ExerciseManager.get as GetFunction).bind(ExerciseManager), [ {
+        this.listenParam('exerciseIdOrUrl', backend, (ExerciseManager.get as GetFunction).bind(ExerciseManager), [ {
             assignment: true,
             members   : true,
             results   : true
diff --git a/ExpressAPI/src/routes/AssignmentRoutes.ts b/ExpressAPI/src/routes/AssignmentRoutes.ts
index ab2bd23456d446fd6a23a64e2bd9db7383b9b05c..fc39e223883f9155e72ca5259d7365dbe9764f78 100644
--- a/ExpressAPI/src/routes/AssignmentRoutes.ts
+++ b/ExpressAPI/src/routes/AssignmentRoutes.ts
@@ -25,6 +25,7 @@ import path                           from 'path';
 import SharedAssignmentHelper         from '../shared/helpers/Dojo/SharedAssignmentHelper';
 import GlobalHelper                   from '../helpers/GlobalHelper';
 import DojoStatusCode                 from '../shared/types/Dojo/DojoStatusCode';
+import DojoModelsHelper               from '../helpers/DojoModelsHelper';
 
 
 class AssignmentRoutes implements RoutesManager {
@@ -45,43 +46,40 @@ class AssignmentRoutes implements RoutesManager {
         }
     };
 
+    private readonly assignmentAddCorrigeValidator: ExpressValidator.Schema = {
+        exerciseIdOrUrl: {
+            trim    : true,
+            notEmpty: true,
+            custom  : DojoValidators.exerciseIdOrUrlValidator
+        }
+    };
+
     registerOnBackend(backend: Express) {
         backend.get('/assignments/:assignmentNameOrUrl', SecurityMiddleware.check(true), this.getAssignment.bind(this));
         backend.post('/assignments', SecurityMiddleware.check(true, SecurityCheckType.TEACHING_STAFF), ParamsValidatorMiddleware.validate(this.assignmentValidator), this.createAssignment.bind(this));
 
-        backend.patch('/assignments/:assignmentNameOrUrl/publish', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_STAFF), this.publishAssignment.bind(this));
-        backend.patch('/assignments/:assignmentNameOrUrl/unpublish', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_STAFF), this.unpublishAssignment.bind(this));
+        backend.patch('/assignments/:assignmentNameOrUrl/publish', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_STAFF), this.changeAssignmentPublishedStatus(true).bind(this));
+        backend.patch('/assignments/:assignmentNameOrUrl/unpublish', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_STAFF), this.changeAssignmentPublishedStatus(false).bind(this));
+
+        backend.post('/assignments/:assignmentNameOrUrl/corrections', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_STAFF), ParamsValidatorMiddleware.validate(this.assignmentAddCorrigeValidator), this.addUpdateAssignmentCorrection(false).bind(this));
+        backend.patch('/assignments/:assignmentNameOrUrl/corrections/:exerciseIdOrUrl', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_STAFF), this.addUpdateAssignmentCorrection(true).bind(this));
     }
 
     // Get an assignment by its name or gitlab url
     private async getAssignment(req: express.Request, res: express.Response) {
-        const assignment: Assignment | undefined = req.boundParams.assignment;
+        const assignment: Partial<Assignment> | undefined = req.boundParams.assignment;
 
-        if ( assignment && !assignment.published && !await AssignmentManager.isUserAllowedToAccessAssignment(assignment, req.session.profile) ) {
-            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
-            // @ts-ignore
+        if ( assignment && !assignment.published && !await AssignmentManager.isUserAllowedToAccessAssignment(assignment as Assignment, req.session.profile) ) {
             delete assignment.gitlabId;
-            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
-            // @ts-ignore
             delete assignment.gitlabLink;
-            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
-            // @ts-ignore
             delete assignment.gitlabCreationInfo;
-            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
-            // @ts-ignore
             delete assignment.gitlabLastInfo;
-            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
-            // @ts-ignore
             delete assignment.gitlabLastInfoDate;
-            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
-            // @ts-ignore
             delete assignment.staff;
-            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
-            // @ts-ignore
             delete assignment.exercises;
         }
 
-        return assignment ? req.session.sendResponse(res, StatusCodes.OK, assignment) : res.status(StatusCodes.NOT_FOUND).send();
+        return assignment ? req.session.sendResponse(res, StatusCodes.OK, DojoModelsHelper.getFullSerializableObject(assignment)) : res.status(StatusCodes.NOT_FOUND).send();
     }
 
     private async createAssignment(req: express.Request, res: express.Response) {
@@ -171,14 +169,6 @@ class AssignmentRoutes implements RoutesManager {
         }
     }
 
-    private async publishAssignment(req: express.Request, res: express.Response) {
-        return this.changeAssignmentPublishedStatus(true)(req, res);
-    }
-
-    private async unpublishAssignment(req: express.Request, res: express.Response) {
-        return this.changeAssignmentPublishedStatus(false)(req, res);
-    }
-
     private changeAssignmentPublishedStatus(publish: boolean): (req: express.Request, res: express.Response) => Promise<void> {
         return async (req: express.Request, res: express.Response): Promise<void> => {
             if ( publish ) {
@@ -213,6 +203,39 @@ class AssignmentRoutes implements RoutesManager {
         };
     }
 
+    private addUpdateAssignmentCorrection(isUpdate: boolean): (req: express.Request, res: express.Response) => Promise<void> {
+        return async (req: express.Request, res: express.Response): Promise<void> => {
+            if ( req.boundParams.exercise?.assignmentName != req.boundParams.assignment?.name ) {
+                return req.session.sendResponse(res, StatusCodes.BAD_REQUEST, undefined, 'The exercise does not belong to the assignment', DojoStatusCode.ASSIGNMENT_EXERCISE_NOT_RELATED);
+            }
+
+            if ( !req.boundParams.assignment?.published ) {
+                return req.session.sendResponse(res, StatusCodes.BAD_REQUEST, undefined, 'The assignment must be public', DojoStatusCode.ASSIGNMENT_NOT_PUBLISHED);
+            }
+
+            if ( !isUpdate && req.boundParams.exercise?.isCorrection ) {
+                return req.session.sendResponse(res, StatusCodes.BAD_REQUEST, undefined, 'This exercise is already a correction', DojoStatusCode.EXERCISE_CORRECTION_ALREADY_EXIST);
+            } else if ( isUpdate && !req.boundParams.exercise?.isCorrection ) {
+                return req.session.sendResponse(res, StatusCodes.BAD_REQUEST, undefined, 'This exercise is not a correction', DojoStatusCode.EXERCISE_CORRECTION_NOT_EXIST);
+            }
+
+            const lastCommit = await GitlabManager.getRepositoryLastCommit(req.boundParams.assignment!.gitlabId);
+            if ( lastCommit ) {
+                await db.exercise.update({
+                                             where: {
+                                                 id: req.boundParams.exercise!.id
+                                             },
+                                             data : {
+                                                 correctionCommit: lastCommit
+                                             }
+                                         });
+
+                return req.session.sendResponse(res, StatusCodes.OK);
+            } else {
+                return req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, undefined, 'No last commit found');
+            }
+        };
+    }
 }
 
 
diff --git a/ExpressAPI/src/routes/ExerciseRoutes.ts b/ExpressAPI/src/routes/ExerciseRoutes.ts
index 0642d3a99433e7d75432d573e8fda1f515f0b936..1317f5b40469d183c88323ee17cf2e5beab4176e 100644
--- a/ExpressAPI/src/routes/ExerciseRoutes.ts
+++ b/ExpressAPI/src/routes/ExerciseRoutes.ts
@@ -72,9 +72,9 @@ class ExerciseRoutes implements RoutesManager {
     registerOnBackend(backend: Express) {
         backend.post('/assignments/:assignmentNameOrUrl/exercises', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_IS_PUBLISHED), ParamsValidatorMiddleware.validate(this.exerciseValidator), this.createExercise.bind(this));
 
-        backend.get('/exercises/:exerciseId/assignment', SecurityMiddleware.check(false, SecurityCheckType.EXERCISE_SECRET), this.getAssignment.bind(this));
+        backend.get('/exercises/:exerciseIdOrUrl/assignment', SecurityMiddleware.check(false, SecurityCheckType.EXERCISE_SECRET), this.getAssignment.bind(this));
 
-        backend.post('/exercises/:exerciseId/results', SecurityMiddleware.check(false, SecurityCheckType.EXERCISE_SECRET), ParamsValidatorMiddleware.validate(this.resultValidator), this.createResult.bind(this));
+        backend.post('/exercises/:exerciseIdOrUrl/results', SecurityMiddleware.check(false, SecurityCheckType.EXERCISE_SECRET), ParamsValidatorMiddleware.validate(this.resultValidator), this.createResult.bind(this));
     }
 
     private getExerciseName(assignment: Assignment, members: Array<GitlabUser>, suffix: number): string {
diff --git a/ExpressAPI/src/shared b/ExpressAPI/src/shared
index 75f67b647da34337f3b220cacf78b2115d6022bc..9e3f29d2f313ef96944a199da0db39f1827c496a 160000
--- a/ExpressAPI/src/shared
+++ b/ExpressAPI/src/shared
@@ -1 +1 @@
-Subproject commit 75f67b647da34337f3b220cacf78b2115d6022bc
+Subproject commit 9e3f29d2f313ef96944a199da0db39f1827c496a
diff --git a/ExpressAPI/src/types/DatabaseTypes.ts b/ExpressAPI/src/types/DatabaseTypes.ts
index 632b05be5eda9eebf30a8c392e5a4020292dd10d..14e9b00a7f35a210302854e69c94dcc2f4dc63b4 100644
--- a/ExpressAPI/src/types/DatabaseTypes.ts
+++ b/ExpressAPI/src/types/DatabaseTypes.ts
@@ -31,6 +31,10 @@ export type User = Prisma.UserGetPayload<typeof userBase> & {
     isAdmin: boolean
     gitlabProfile: LazyVal<GitlabUser>
 }
-export type Assignment = Prisma.AssignmentGetPayload<typeof assignmentBase>
-export type Exercise = Prisma.ExerciseGetPayload<typeof exerciseBase>
+export type Exercise = Prisma.ExerciseGetPayload<typeof exerciseBase> & {
+    isCorrection: boolean
+}
+export type Assignment = Prisma.AssignmentGetPayload<typeof assignmentBase> & {
+    corrections: LazyVal<Array<Exercise>>
+}
 export type Result = Prisma.ResultGetPayload<typeof resultBase>
\ No newline at end of file