From 0f8bd3df6a483a9e3e08eb8d019760d899748264 Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Sun, 23 Feb 2025 13:56:40 +0100 Subject: [PATCH 001/180] chore: Basic logging met loki --- backend/src/app.ts | 29 ++++++++++++++++++++- config/loki-config.yml | 30 ++++++++++++++++++++++ docker-compose.yml | 36 ++++++++++++++++---------- package-lock.json | 58 +++++++++++++++++++++++++++++++++++------- package.json | 3 +++ 5 files changed, 133 insertions(+), 23 deletions(-) create mode 100644 config/loki-config.yml diff --git a/backend/src/app.ts b/backend/src/app.ts index 65dd8a7a..756cf409 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -19,4 +19,31 @@ async function startServer() { }); } -startServer(); + +import { LokiClient, LogError, LokiLabels, LogInfo } from 'loki-logger-ts'; + +const HostData = { + url: "http://localhost:3100/loki/api/v1/push", +}; + +const labels: LokiLabels = { + source: "Test", + job: "TestJob", + host: "localhost", +}; + +async function main() { + const client = new LokiClient(HostData.url); + + const msg = 'Hello World'; + await LogError(client, msg, labels); + await LogInfo(client, 'Dit is een goed bericht', labels); + + console.log(client.showMetrics()); + + console.log(client.getMetrics()); +} + +main(); + +// startServer(); diff --git a/config/loki-config.yml b/config/loki-config.yml new file mode 100644 index 00000000..bedf3c80 --- /dev/null +++ b/config/loki-config.yml @@ -0,0 +1,30 @@ + +# This is a complete configuration to deploy Loki backed by the filesystem. +# The index will be shipped to the storage via tsdb-shipper. + +auth_enabled: false + +server: + http_listen_port: 3100 + +common: + ring: + instance_addr: 127.0.0.1 + kvstore: + store: inmemory + replication_factor: 1 + path_prefix: /tmp/loki + +schema_config: + configs: + - from: 2020-05-15 + store: tsdb + object_store: filesystem + schema: v13 + index: + prefix: index_ + period: 24h + +storage_config: + filesystem: + directory: /tmp/loki/chunks diff --git a/docker-compose.yml b/docker-compose.yml index e8efb530..b29b1470 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,16 +1,26 @@ services: - db: - image: postgres:latest - environment: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: postgres - ports: - - "5432:5432" - network_mode: "host" - volumes: - - postgres_data:/var/lib/postgresql/data - - ./backend/config/db/init.sql:/docker-entrypoint-initdb.d/init.sql + db: + image: postgres:latest + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + - '5432:5432' + network_mode: 'host' + volumes: + - dwengo_postgres_data:/var/lib/postgresql/data + - ./backend/config/db/init.sql:/docker-entrypoint-initdb.d/init.sql + + logging: + image: grafana/loki:latest + ports: + - '3100:3100' + - '9095:9095' + network_mode: 'host' + volumes: + - ./config/loki-config.yml:/etc/loki/config.yaml + command: -config.file=/etc/loki/config.yaml volumes: - postgres_data: + dwengo_postgres_data: diff --git a/package-lock.json b/package-lock.json index a00e4f54..394ee797 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,10 +7,14 @@ "": { "name": "dwengo-1-monorepo", "version": "0.0.1", + "license": "MIT", "workspaces": [ "backend", "frontend" ], + "dependencies": { + "loki-logger-ts": "^1.0.2" + }, "devDependencies": { "@eslint/compat": "^1.2.6", "@eslint/js": "^9.20.0", @@ -26,7 +30,6 @@ "backend": { "name": "dwengo-1-backend", "version": "0.0.1", - "license": "MIT", "dependencies": { "@mikro-orm/core": "^6.4.6", "@mikro-orm/postgresql": "^6.4.6", @@ -3142,9 +3145,19 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true, "license": "MIT" }, + "node_modules/axios": { + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3510,7 +3523,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" @@ -3778,7 +3790,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.4.0" @@ -3993,7 +4004,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -4735,6 +4745,26 @@ "dev": true, "license": "ISC" }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/foreground-child": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", @@ -4756,7 +4786,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", - "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -4772,7 +4801,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -4782,7 +4810,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -5067,7 +5094,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -5786,6 +5812,14 @@ "dev": true, "license": "MIT" }, + "node_modules/loki-logger-ts": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/loki-logger-ts/-/loki-logger-ts-1.0.2.tgz", + "integrity": "sha512-SV/B5o+9jaxiThcU5N3LUxCNTx20IgR9xjCjx/ED/pVc/097mqKSRpmvSjvx9ezFcjJlUF7GBkrBBpR6veNp7Q==", + "dependencies": { + "axios": "^1.4.0" + } + }, "node_modules/loupe": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", @@ -6763,6 +6797,12 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", diff --git a/package.json b/package.json index 59a2e01d..ff3ceb88 100644 --- a/package.json +++ b/package.json @@ -34,5 +34,8 @@ "eslint-config-prettier": "^10.0.1", "jiti": "^2.4.2", "typescript-eslint": "^8.24.1" + }, + "dependencies": { + "loki-logger-ts": "^1.0.2" } } From 7fd6305fd9f039ce956872a5cf2d84dd9a7562f8 Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Sun, 23 Feb 2025 17:29:11 +0100 Subject: [PATCH 002/180] chore(backend): Loki configureren De meeste console statements vervangen door Loki --- backend/package.json | 6 +- backend/src/app.ts | 41 +- backend/src/logging/initalize.ts | 47 ++ backend/src/logging/responseTimeLogger.ts | 23 + backend/src/orm.ts | 7 + config/{loki-config.yml => loki/config.yml} | 2 +- docker-compose.yml | 18 +- package-lock.json | 663 +++++++++++++++++++- 8 files changed, 767 insertions(+), 40 deletions(-) create mode 100644 backend/src/logging/initalize.ts create mode 100644 backend/src/logging/responseTimeLogger.ts rename config/{loki-config.yml => loki/config.yml} (95%) diff --git a/backend/package.json b/backend/package.json index 85a4d255..84a4e23e 100644 --- a/backend/package.json +++ b/backend/package.json @@ -18,12 +18,16 @@ "@mikro-orm/postgresql": "^6.4.6", "@mikro-orm/reflection": "^6.4.6", "dotenv": "^16.4.7", - "express": "^5.0.1" + "express": "^5.0.1", + "response-time": "^2.3.3", + "winston": "^3.17.0", + "winston-loki": "^6.1.3" }, "devDependencies": { "@mikro-orm/cli": "^6.4.6", "@types/express": "^5.0.0", "@types/node": "^22.13.4", + "@types/response-time": "^2.3.8", "globals": "^15.15.0", "ts-node": "^10.9.2", "tsx": "^4.19.3", diff --git a/backend/src/app.ts b/backend/src/app.ts index 756cf409..29807f6b 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -1,11 +1,21 @@ import express, { Express, Response } from 'express'; import initORM from './orm.js'; +import { getLogger } from './logging/initalize.js'; +import { responseTimeLogger } from './logging/responseTimeLogger.js'; +import responseTime from 'response-time'; +import { Logger } from 'winston'; + +const logger: Logger = getLogger(); const app: Express = express(); const port: string | number = process.env.PORT || 3000; +app.use(express.json()); +app.use(responseTime(responseTimeLogger)); + // TODO Replace with Express routes app.get('/', (_, res: Response) => { + logger.debug('GET /'); res.json({ message: 'Hello Dwengo!', }); @@ -15,35 +25,8 @@ async function startServer() { await initORM(); app.listen(port, () => { - console.log(`Server is running at http://localhost:${port}`); + logger.info(`Server is running at http://localhost:${port}`); }); } - -import { LokiClient, LogError, LokiLabels, LogInfo } from 'loki-logger-ts'; - -const HostData = { - url: "http://localhost:3100/loki/api/v1/push", -}; - -const labels: LokiLabels = { - source: "Test", - job: "TestJob", - host: "localhost", -}; - -async function main() { - const client = new LokiClient(HostData.url); - - const msg = 'Hello World'; - await LogError(client, msg, labels); - await LogInfo(client, 'Dit is een goed bericht', labels); - - console.log(client.showMetrics()); - - console.log(client.getMetrics()); -} - -main(); - -// startServer(); +startServer(); diff --git a/backend/src/logging/initalize.ts b/backend/src/logging/initalize.ts new file mode 100644 index 00000000..6a4d52c5 --- /dev/null +++ b/backend/src/logging/initalize.ts @@ -0,0 +1,47 @@ +import { createLogger, format, Logger, transports } from 'winston'; +import LokiTransport from 'winston-loki'; +import { LokiLabels } from 'loki-logger-ts'; + +const LoggingLevel = 'development' === process.env.NODE_ENV ? 'debug' : 'info'; +const Host = 'http://localhost:3102'; +const Labels: LokiLabels = { + source: 'Dwengo-Backend', + job: 'Dwengo-Backend', + host: 'localhost', +}; + +let logger: Logger; + +function initializeLogger() { + if (logger !== undefined) { + return logger; + } + + const lokiTransport: LokiTransport = new LokiTransport({ + host: Host, + labels: Labels, + level: LoggingLevel, + json: true, + format: format.combine(format.timestamp(), format.json()), + onConnectionError: (err) => { + console.error(`Connection error: ${err}`); + }, + }); + + const consoleTransport = new transports.Console({ + level: LoggingLevel, + format: format.combine(format.simple(), format.colorize()), + }); + + logger = createLogger({ + transports: [lokiTransport, consoleTransport], + }); + + logger.debug('Logger initialized'); + return logger; +} + +export function getLogger(): Logger { + logger ||= initializeLogger(); + return logger; +} diff --git a/backend/src/logging/responseTimeLogger.ts b/backend/src/logging/responseTimeLogger.ts new file mode 100644 index 00000000..5baf63f4 --- /dev/null +++ b/backend/src/logging/responseTimeLogger.ts @@ -0,0 +1,23 @@ +import { getLogger } from './initalize.js'; +import { Logger } from 'winston'; +import { Request, Response } from 'express'; + +export function responseTimeLogger(req: Request, res: Response, time: number) { + const logger: Logger = getLogger(); + + const method = req.method; + const url = req.url; + const status = res.statusCode; + + logger.info({ + message: 'Request completed', + method: method, + url: url, + status: status, + responseTime: Number(time), + labels: { + origin: 'api', + type: 'responseTime', + }, + }); +} diff --git a/backend/src/orm.ts b/backend/src/orm.ts index d9de328f..f4dbf0e9 100644 --- a/backend/src/orm.ts +++ b/backend/src/orm.ts @@ -1,6 +1,13 @@ import { MikroORM } from '@mikro-orm/core'; import config from './mikro-orm.config.js'; +import { getLogger } from './logging/initalize.js'; +import { Logger } from 'winston'; export default async function initORM() { + const logger: Logger = getLogger(); + + logger.info('Initializing ORM'); + logger.debug('MikroORM config is', config); + await MikroORM.init(config); } diff --git a/config/loki-config.yml b/config/loki/config.yml similarity index 95% rename from config/loki-config.yml rename to config/loki/config.yml index bedf3c80..f5ba3799 100644 --- a/config/loki-config.yml +++ b/config/loki/config.yml @@ -5,7 +5,7 @@ auth_enabled: false server: - http_listen_port: 3100 + http_listen_port: 3102 common: ring: diff --git a/docker-compose.yml b/docker-compose.yml index b29b1470..1f8a4c98 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,6 @@ services: POSTGRES_DB: postgres ports: - '5432:5432' - network_mode: 'host' volumes: - dwengo_postgres_data:/var/lib/postgresql/data - ./backend/config/db/init.sql:/docker-entrypoint-initdb.d/init.sql @@ -15,12 +14,23 @@ services: logging: image: grafana/loki:latest ports: - - '3100:3100' + - '3102:3102' - '9095:9095' - network_mode: 'host' volumes: - - ./config/loki-config.yml:/etc/loki/config.yaml + - ./config/loki/config.yml:/etc/loki/config.yaml + - dwengo_loki_data:/loki command: -config.file=/etc/loki/config.yaml + restart: unless-stopped + + dashboards: + image: grafana/grafana:latest + ports: + - '3000:3000' + volumes: + - dwengo_grafana_data:/var/lib/grafana + restart: unless-stopped volumes: dwengo_postgres_data: + dwengo_loki_data: + dwengo_grafana_data: diff --git a/package-lock.json b/package-lock.json index 394ee797..f9d4faf4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,12 +35,16 @@ "@mikro-orm/postgresql": "^6.4.6", "@mikro-orm/reflection": "^6.4.6", "dotenv": "^16.4.7", - "express": "^5.0.1" + "express": "^5.0.1", + "response-time": "^2.3.3", + "winston": "^3.17.0", + "winston-loki": "^6.1.3" }, "devDependencies": { "@mikro-orm/cli": "^6.4.6", "@types/express": "^5.0.0", "@types/node": "^22.13.4", + "@types/response-time": "^2.3.8", "globals": "^15.15.0", "ts-node": "^10.9.2", "tsx": "^4.19.3", @@ -647,6 +651,15 @@ "node": ">=6.9.0" } }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -775,6 +788,17 @@ "node": ">=18" } }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "license": "MIT", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.0", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", @@ -1674,6 +1698,214 @@ "@mikro-orm/core": "^6.0.0" } }, + "node_modules/@napi-rs/snappy-android-arm-eabi": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-android-arm-eabi/-/snappy-android-arm-eabi-7.2.2.tgz", + "integrity": "sha512-H7DuVkPCK5BlAr1NfSU8bDEN7gYs+R78pSHhDng83QxRnCLmVIZk33ymmIwurmoA1HrdTxbkbuNl+lMvNqnytw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-android-arm64": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-android-arm64/-/snappy-android-arm64-7.2.2.tgz", + "integrity": "sha512-2R/A3qok+nGtpVK8oUMcrIi5OMDckGYNoBLFyli3zp8w6IArPRfg1yOfVUcHvpUDTo9T7LOS1fXgMOoC796eQw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-darwin-arm64": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-darwin-arm64/-/snappy-darwin-arm64-7.2.2.tgz", + "integrity": "sha512-USgArHbfrmdbuq33bD5ssbkPIoT7YCXCRLmZpDS6dMDrx+iM7eD2BecNbOOo7/v1eu6TRmQ0xOzeQ6I/9FIi5g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-darwin-x64": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-darwin-x64/-/snappy-darwin-x64-7.2.2.tgz", + "integrity": "sha512-0APDu8iO5iT0IJKblk2lH0VpWSl9zOZndZKnBYIc+ei1npw2L5QvuErFOTeTdHBtzvUHASB+9bvgaWnQo4PvTQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-freebsd-x64": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-freebsd-x64/-/snappy-freebsd-x64-7.2.2.tgz", + "integrity": "sha512-mRTCJsuzy0o/B0Hnp9CwNB5V6cOJ4wedDTWEthsdKHSsQlO7WU9W1yP7H3Qv3Ccp/ZfMyrmG98Ad7u7lG58WXA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-linux-arm-gnueabihf": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-arm-gnueabihf/-/snappy-linux-arm-gnueabihf-7.2.2.tgz", + "integrity": "sha512-v1uzm8+6uYjasBPcFkv90VLZ+WhLzr/tnfkZ/iD9mHYiULqkqpRuC8zvc3FZaJy5wLQE9zTDkTJN1IvUcZ+Vcg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-linux-arm64-gnu": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-arm64-gnu/-/snappy-linux-arm64-gnu-7.2.2.tgz", + "integrity": "sha512-LrEMa5pBScs4GXWOn6ZYXfQ72IzoolZw5txqUHVGs8eK4g1HR9HTHhb2oY5ySNaKakG5sOgMsb1rwaEnjhChmQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-linux-arm64-musl": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-arm64-musl/-/snappy-linux-arm64-musl-7.2.2.tgz", + "integrity": "sha512-3orWZo9hUpGQcB+3aTLW7UFDqNCQfbr0+MvV67x8nMNYj5eAeUtMmUE/HxLznHO4eZ1qSqiTwLbVx05/Socdlw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-linux-x64-gnu": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-x64-gnu/-/snappy-linux-x64-gnu-7.2.2.tgz", + "integrity": "sha512-jZt8Jit/HHDcavt80zxEkDpH+R1Ic0ssiVCoueASzMXa7vwPJeF4ZxZyqUw4qeSy7n8UUExomu8G8ZbP6VKhgw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-linux-x64-musl": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-x64-musl/-/snappy-linux-x64-musl-7.2.2.tgz", + "integrity": "sha512-Dh96IXgcZrV39a+Tej/owcd9vr5ihiZ3KRix11rr1v0MWtVb61+H1GXXlz6+Zcx9y8jM1NmOuiIuJwkV4vZ4WA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-win32-arm64-msvc": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-win32-arm64-msvc/-/snappy-win32-arm64-msvc-7.2.2.tgz", + "integrity": "sha512-9No0b3xGbHSWv2wtLEn3MO76Yopn1U2TdemZpCaEgOGccz1V+a/1d16Piz3ofSmnA13HGFz3h9NwZH9EOaIgYA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-win32-ia32-msvc": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-win32-ia32-msvc/-/snappy-win32-ia32-msvc-7.2.2.tgz", + "integrity": "sha512-QiGe+0G86J74Qz1JcHtBwM3OYdTni1hX1PFyLRo3HhQUSpmi13Bzc1En7APn+6Pvo7gkrcy81dObGLDSxFAkQQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-win32-x64-msvc": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-win32-x64-msvc/-/snappy-win32-x64-msvc-7.2.2.tgz", + "integrity": "sha512-a43cyx1nK0daw6BZxVcvDEXxKMFLSBSDTAhsFD0VqSKcC7MGUBMaqyoWUcMiI7LBSz4bxUmxDWKfCYzpEmeb3w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1763,6 +1995,70 @@ "dev": true, "license": "MIT" }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, "node_modules/@rollup/pluginutils": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", @@ -2229,7 +2525,6 @@ "version": "22.13.4", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.4.tgz", "integrity": "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.20.0" @@ -2249,6 +2544,17 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/response-time": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@types/response-time/-/response-time-2.3.8.tgz", + "integrity": "sha512-7qGaNYvdxc0zRab8oHpYx7AW17qj+G0xuag1eCrw3M2VWPJQ/HyKaaghWygiaOUl0y9x7QGQwppDpqLJ5V9pzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/node": "*" + } + }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", @@ -2279,6 +2585,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.24.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.1.tgz", @@ -3141,6 +3453,21 @@ "node": ">=12" } }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" + }, + "node_modules/async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -3270,6 +3597,18 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/btoa": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", + "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==", + "license": "(MIT OR Apache-2.0)", + "bin": { + "btoa": "bin/btoa.js" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/bundle-name": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", @@ -3493,6 +3832,16 @@ "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", "license": "MIT" }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3510,7 +3859,31 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "license": "MIT" }, "node_modules/colorette": { @@ -3519,6 +3892,16 @@ "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", "license": "MIT" }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "license": "MIT", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -3932,6 +4315,12 @@ "dev": true, "license": "MIT" }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "license": "MIT" + }, "node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", @@ -4611,6 +5000,12 @@ "reusify": "^1.0.4" } }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "license": "MIT" + }, "node_modules/figlet": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.8.0.tgz", @@ -4745,6 +5140,12 @@ "dev": true, "license": "ISC" }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "license": "MIT" + }, "node_modules/follow-redirects": { "version": "1.15.9", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", @@ -5293,6 +5694,12 @@ "node": ">= 0.10" } }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT" + }, "node_modules/is-core-module": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", @@ -5769,6 +6176,12 @@ "dev": true, "license": "MIT" }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "license": "MIT" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5812,6 +6225,23 @@ "dev": true, "license": "MIT" }, + "node_modules/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "license": "MIT", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/loki-logger-ts": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/loki-logger-ts/-/loki-logger-ts-1.0.2.tgz", @@ -5820,6 +6250,12 @@ "axios": "^1.4.0" } }, + "node_modules/long": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.1.tgz", + "integrity": "sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng==", + "license": "Apache-2.0" + }, "node_modules/loupe": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", @@ -6222,6 +6658,15 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -6231,6 +6676,15 @@ "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "license": "MIT", + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/open": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", @@ -6784,6 +7238,30 @@ "dev": true, "license": "ISC" }, + "node_modules/protobufjs": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", + "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -6898,6 +7376,20 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/rechoir": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", @@ -6966,6 +7458,19 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, + "node_modules/response-time": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/response-time/-/response-time-2.3.3.tgz", + "integrity": "sha512-SsjjOPHl/FfrTQNgmc5oen8Hr1Jxpn6LlHNXxCIFdYMHuK1kMeYMobb9XN3mvxaGQm3dbegqYFMX4+GDORfbWg==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "on-headers": "~1.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -7099,6 +7604,15 @@ ], "license": "MIT" }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -7333,6 +7847,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/sirv": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", @@ -7357,6 +7880,35 @@ "node": ">=8" } }, + "node_modules/snappy": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/snappy/-/snappy-7.2.2.tgz", + "integrity": "sha512-iADMq1kY0v3vJmGTuKcFWSXt15qYUz7wFkArOrsSg0IFfI3nJqIJvK2/ZbEIndg7erIJLtAVX2nSOqPz7DcwbA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/snappy-android-arm-eabi": "7.2.2", + "@napi-rs/snappy-android-arm64": "7.2.2", + "@napi-rs/snappy-darwin-arm64": "7.2.2", + "@napi-rs/snappy-darwin-x64": "7.2.2", + "@napi-rs/snappy-freebsd-x64": "7.2.2", + "@napi-rs/snappy-linux-arm-gnueabihf": "7.2.2", + "@napi-rs/snappy-linux-arm64-gnu": "7.2.2", + "@napi-rs/snappy-linux-arm64-musl": "7.2.2", + "@napi-rs/snappy-linux-x64-gnu": "7.2.2", + "@napi-rs/snappy-linux-x64-musl": "7.2.2", + "@napi-rs/snappy-win32-arm64-msvc": "7.2.2", + "@napi-rs/snappy-win32-ia32-msvc": "7.2.2", + "@napi-rs/snappy-win32-x64-msvc": "7.2.2" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -7394,6 +7946,15 @@ "node": ">= 0.6" } }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -7417,6 +7978,15 @@ "dev": true, "license": "MIT" }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -7634,6 +8204,12 @@ "node": ">=8.0.0" } }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "license": "MIT" + }, "node_modules/tildify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", @@ -7764,6 +8340,15 @@ "node": ">=18" } }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/ts-api-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", @@ -7970,7 +8555,6 @@ "version": "6.20.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, "license": "MIT" }, "node_modules/unicorn-magic": { @@ -8045,11 +8629,16 @@ "punycode": "^2.1.0" } }, + "node_modules/url-polyfill": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/url-polyfill/-/url-polyfill-1.1.13.tgz", + "integrity": "sha512-tXzkojrv2SujumYthZ/WjF7jaSfNhSXlYMpE5AYdL2I3D7DCeo+mch8KtW2rUuKjDg+3VXODXHVgipt8yGY/eQ==", + "license": "MIT" + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, "license": "MIT" }, "node_modules/utils-merge": { @@ -9084,6 +9673,70 @@ "node": ">=8" } }, + "node_modules/winston": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "license": "MIT", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-loki": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/winston-loki/-/winston-loki-6.1.3.tgz", + "integrity": "sha512-DjWtJ230xHyYQWr9mZJa93yhwHttn3JEtSYWP8vXZWJOahiQheUhf+88dSIidbGXB3u0oLweV6G1vkL/ouT62Q==", + "license": "MIT", + "dependencies": { + "async-exit-hook": "2.0.1", + "btoa": "^1.2.1", + "protobufjs": "^7.2.4", + "url-polyfill": "^1.1.12", + "winston-transport": "^4.3.0" + }, + "optionalDependencies": { + "snappy": "^7.2.2" + } + }, + "node_modules/winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "license": "MIT", + "dependencies": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", From 9a96e480cd972b497d00c5cee79cc729e0e525f9 Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Sun, 23 Feb 2025 17:30:16 +0100 Subject: [PATCH 003/180] chore: Environments in npm commandos --- backend/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/package.json b/backend/package.json index 84a4e23e..008afecf 100644 --- a/backend/package.json +++ b/backend/package.json @@ -5,9 +5,9 @@ "private": true, "type": "module", "scripts": { - "build": "tsc --project tsconfig.json", - "dev": "tsx watch --env-file=.env.development.local src/app.ts", - "start": "node --env-file=.env dist/app.js", + "build": "NODE_ENV=production tsc --project tsconfig.json", + "dev": "NODE_ENV=development tsx watch --env-file=.env.development.local src/app.ts", + "start": "NODE_ENV=production node --env-file=.env dist/app.js", "format": "prettier --write src/", "format-check": "prettier --check src/", "lint": "eslint . --fix", From 0fc5a992696400e2be22b1fbd9434adeef5cfef4 Mon Sep 17 00:00:00 2001 From: Timo De Meyst Date: Fri, 28 Feb 2025 20:23:46 +0100 Subject: [PATCH 004/180] chore: lint-action workflow toegevoegd --- .github/workflows/lint-action.yml | 40 +++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .github/workflows/lint-action.yml diff --git a/.github/workflows/lint-action.yml b/.github/workflows/lint-action.yml new file mode 100644 index 00000000..145e820b --- /dev/null +++ b/.github/workflows/lint-action.yml @@ -0,0 +1,40 @@ +name: Lint + +on: + # Trigger the workflow on push or pull request, + # but only for the main branch + push: + # Replace pull_request with pull_request_target if you + # plan to use this action with forks, see the Limitations section + pull_request: + branches: + - dev + +# Down scope as necessary via https://docs.github.com/en/actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token +permissions: + checks: write + contents: write + +jobs: + run-linters: + name: Run linters + runs-on: [self-hosted, Linux, X64] + + steps: + - name: Check out Git repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + # ESLint and Prettier must be in `package.json` + - name: Install Node.js dependencies + run: npm ci + + - name: Run linters + uses: wearerequired/lint-action@v2 + with: + eslint: true + prettier: true \ No newline at end of file From f8ba6ad4883b8051a4482e84f0a827f21955344b Mon Sep 17 00:00:00 2001 From: Timo De Meyst Date: Fri, 28 Feb 2025 20:32:48 +0100 Subject: [PATCH 005/180] chore: eslint config (ignore .github, include .ts files, gebruik config bestand) --- .github/workflows/lint-action.yml | 1 + eslint.config.ts | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint-action.yml b/.github/workflows/lint-action.yml index 145e820b..77cc9568 100644 --- a/.github/workflows/lint-action.yml +++ b/.github/workflows/lint-action.yml @@ -37,4 +37,5 @@ jobs: uses: wearerequired/lint-action@v2 with: eslint: true + eslint_args: "--config eslint.config.ts" prettier: true \ No newline at end of file diff --git a/eslint.config.ts b/eslint.config.ts index 7d657c67..52813c36 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -16,7 +16,13 @@ export default [ prettierConfig, includeIgnoreFile(gitignorePath), { - ignores: ['**/dist/**', '**/.node_modules/**', '**/coverage/**'], + ignores: ['**/dist/**', '**/.node_modules/**', '**/coverage/**', '/.github/**'], + files: [ + "**/*.ts", + "**/*.cts", + "**.*.mts", + "**/*.ts" + ] }, { languageOptions: { From 0a02ee9eb0925472b92ade176d36261b16e1cf20 Mon Sep 17 00:00:00 2001 From: Timo De Meyst Date: Fri, 28 Feb 2025 20:44:12 +0100 Subject: [PATCH 006/180] chore: test lint-action --- package-lock.json | 504 +--------------------------------------------- 1 file changed, 6 insertions(+), 498 deletions(-) diff --git a/package-lock.json b/package-lock.json index a00e4f54..aaef6b03 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "dwengo-1-monorepo", "version": "0.0.1", + "license": "MIT", "workspaces": [ "backend", "frontend" @@ -26,7 +27,6 @@ "backend": { "name": "dwengo-1-backend", "version": "0.0.1", - "license": "MIT", "dependencies": { "@mikro-orm/core": "^6.4.6", "@mikro-orm/postgresql": "^6.4.6", @@ -785,7 +785,6 @@ "os": [ "aix" ], - "peer": true, "engines": { "node": ">=18" } @@ -803,7 +802,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -821,7 +819,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -839,7 +836,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -857,7 +853,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } @@ -875,7 +870,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } @@ -893,7 +887,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -911,7 +904,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -929,7 +921,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -947,7 +938,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -965,7 +955,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -983,7 +972,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1001,7 +989,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1019,7 +1006,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1037,7 +1023,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1055,7 +1040,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1073,7 +1057,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1091,7 +1074,6 @@ "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -1109,7 +1091,6 @@ "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -1127,7 +1108,6 @@ "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -1145,7 +1125,6 @@ "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -1163,7 +1142,6 @@ "os": [ "sunos" ], - "peer": true, "engines": { "node": ">=18" } @@ -1181,7 +1159,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -1199,7 +1176,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -1217,7 +1193,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -8038,14 +8013,13 @@ } }, "node_modules/vite": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.1.1.tgz", - "integrity": "sha512-4GgM54XrwRfrOp297aIYspIti66k56v16ZnqHvrIM7mG+HjDlAwS7p+Srr7J6fGvEdOJ5JcQ/D9T7HhtdXDTzA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.0.tgz", + "integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==", "dev": true, - "license": "MIT", "dependencies": { - "esbuild": "^0.24.2", - "postcss": "^8.5.2", + "esbuild": "^0.25.0", + "postcss": "^8.5.3", "rollup": "^4.30.1" }, "bin": { @@ -8220,472 +8194,6 @@ "vite": "^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0" } }, - "node_modules/vite/node_modules/@esbuild/aix-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", - "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", - "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", - "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", - "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", - "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", - "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", - "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", - "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", - "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", - "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", - "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", - "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", - "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", - "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", - "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", - "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", - "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", - "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", - "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", - "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", - "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", - "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", - "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", - "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", - "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/esbuild": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", - "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.24.2", - "@esbuild/android-arm": "0.24.2", - "@esbuild/android-arm64": "0.24.2", - "@esbuild/android-x64": "0.24.2", - "@esbuild/darwin-arm64": "0.24.2", - "@esbuild/darwin-x64": "0.24.2", - "@esbuild/freebsd-arm64": "0.24.2", - "@esbuild/freebsd-x64": "0.24.2", - "@esbuild/linux-arm": "0.24.2", - "@esbuild/linux-arm64": "0.24.2", - "@esbuild/linux-ia32": "0.24.2", - "@esbuild/linux-loong64": "0.24.2", - "@esbuild/linux-mips64el": "0.24.2", - "@esbuild/linux-ppc64": "0.24.2", - "@esbuild/linux-riscv64": "0.24.2", - "@esbuild/linux-s390x": "0.24.2", - "@esbuild/linux-x64": "0.24.2", - "@esbuild/netbsd-arm64": "0.24.2", - "@esbuild/netbsd-x64": "0.24.2", - "@esbuild/openbsd-arm64": "0.24.2", - "@esbuild/openbsd-x64": "0.24.2", - "@esbuild/sunos-x64": "0.24.2", - "@esbuild/win32-arm64": "0.24.2", - "@esbuild/win32-ia32": "0.24.2", - "@esbuild/win32-x64": "0.24.2" - } - }, "node_modules/vite/node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", From 24b064e53ac122e45ebd36415f03d9ab1006a384 Mon Sep 17 00:00:00 2001 From: Timo De Meyst Date: Fri, 28 Feb 2025 20:48:06 +0100 Subject: [PATCH 007/180] chore: map toegevoegd aan eslint args --- .github/workflows/lint-action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-action.yml b/.github/workflows/lint-action.yml index 77cc9568..aef8f090 100644 --- a/.github/workflows/lint-action.yml +++ b/.github/workflows/lint-action.yml @@ -37,5 +37,5 @@ jobs: uses: wearerequired/lint-action@v2 with: eslint: true - eslint_args: "--config eslint.config.ts" + eslint_args: "--config eslint.config.ts ./" prettier: true \ No newline at end of file From 4c5799ec0ed9ea78c3798d533ac697a1f7a90bca Mon Sep 17 00:00:00 2001 From: Timo De Meyst Date: Fri, 28 Feb 2025 20:50:07 +0100 Subject: [PATCH 008/180] debug: debug flag meegegeven aan eslint args --- .github/workflows/lint-action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-action.yml b/.github/workflows/lint-action.yml index aef8f090..2f5df3a1 100644 --- a/.github/workflows/lint-action.yml +++ b/.github/workflows/lint-action.yml @@ -37,5 +37,5 @@ jobs: uses: wearerequired/lint-action@v2 with: eslint: true - eslint_args: "--config eslint.config.ts ./" + eslint_args: "--debug --config eslint.config.ts ./" prettier: true \ No newline at end of file From 3287539419e4f81cc7c1ff83236e9abe0bf480e5 Mon Sep 17 00:00:00 2001 From: Timo De Meyst Date: Fri, 28 Feb 2025 20:58:07 +0100 Subject: [PATCH 009/180] chore: lint-action gebruik forked action Gebruik de fork van rkuykendall om eslint v9 te ondersteunen --- .github/workflows/lint-action.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint-action.yml b/.github/workflows/lint-action.yml index 2f5df3a1..8ca45244 100644 --- a/.github/workflows/lint-action.yml +++ b/.github/workflows/lint-action.yml @@ -34,8 +34,9 @@ jobs: run: npm ci - name: Run linters - uses: wearerequired/lint-action@v2 + uses: rkuykendall/lint-action@master with: + auto_fix: true eslint: true - eslint_args: "--debug --config eslint.config.ts ./" + eslint_args: "--debug --config eslint.config.ts" prettier: true \ No newline at end of file From f5348c6848ff917e12e75b14846d9e0a9aa30b43 Mon Sep 17 00:00:00 2001 From: Timo De Meyst Date: Fri, 28 Feb 2025 20:59:30 +0100 Subject: [PATCH 010/180] chore: update eslint config ignore path voor .github veranderd --- eslint.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eslint.config.ts b/eslint.config.ts index 52813c36..7e0ec525 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -16,7 +16,7 @@ export default [ prettierConfig, includeIgnoreFile(gitignorePath), { - ignores: ['**/dist/**', '**/.node_modules/**', '**/coverage/**', '/.github/**'], + ignores: ['**/dist/**', '**/.node_modules/**', '**/coverage/**', '**/.github/**'], files: [ "**/*.ts", "**/*.cts", From 3df8bfe3a7e90c0d39baaebd566ee96fd2099cf6 Mon Sep 17 00:00:00 2001 From: Timo De Meyst Date: Fri, 28 Feb 2025 21:03:21 +0100 Subject: [PATCH 011/180] chore: prettierignore toegevoegd --- .prettierignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .prettierignore diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..37425f5e --- /dev/null +++ b/.prettierignore @@ -0,0 +1,2 @@ +#Ignore .github files +**/.github/** \ No newline at end of file From 7746d6b41252ab5c7dbc6c73f91995f6c6841bad Mon Sep 17 00:00:00 2001 From: Timo De Meyst Date: Fri, 28 Feb 2025 21:09:36 +0100 Subject: [PATCH 012/180] chore: .prettierignore met alles uit .gitignore --- .prettierignore | 742 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 741 insertions(+), 1 deletion(-) diff --git a/.prettierignore b/.prettierignore index 37425f5e..72394bfe 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,742 @@ #Ignore .github files -**/.github/** \ No newline at end of file +**/.github/** + +# ---> Node +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# package-lock.json +backend/package-lock.json + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# ---> Vue +# gitignore template for Vue.js projects +# +# Recommended template: Node.gitignore + +# TODO: where does this rule come from? +docs/_book + +# TODO: where does this rule come from? +test/ + +# ---> JetBrains +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +# ---> VisualStudio +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml + +# ---> VisualStudioCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +# ---> macOS +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# ---> Vim +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +# ---> Emacs +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + +# network security +/network-security.data + From 9f88737c488d2c6339f6b4e816fc6e154e878db0 Mon Sep 17 00:00:00 2001 From: Timo De Meyst Date: Fri, 28 Feb 2025 21:11:20 +0100 Subject: [PATCH 013/180] chore: commit message voor lint-action veranderd --- .github/workflows/lint-action.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint-action.yml b/.github/workflows/lint-action.yml index 8ca45244..98bfa848 100644 --- a/.github/workflows/lint-action.yml +++ b/.github/workflows/lint-action.yml @@ -38,5 +38,6 @@ jobs: with: auto_fix: true eslint: true - eslint_args: "--debug --config eslint.config.ts" - prettier: true \ No newline at end of file + eslint_args: "--config eslint.config.ts" + prettier: true + commit_message: "style: fix linting issues met lint-action" \ No newline at end of file From aeab6aee61a25a0dca4ac929b091fbe88b37088d Mon Sep 17 00:00:00 2001 From: Lint Action Date: Fri, 28 Feb 2025 20:11:48 +0000 Subject: [PATCH 014/180] style: fix linting issues met lint-action --- .vscode/extensions.json | 16 +++++++-------- .vscode/settings.json | 22 ++++++++++---------- backend/tests/example.test.ts | 8 ++++---- backend/tsconfig.json | 4 +--- docker-compose.yml | 24 +++++++++++----------- eslint.config.ts | 14 ++++++------- frontend/e2e/vue.spec.ts | 8 ++++---- frontend/eslint.config.ts | 38 +++++++++++++++-------------------- frontend/index.html | 15 +++++++++++--- frontend/playwright.config.ts | 28 ++++++++++++-------------- frontend/prettier.config.js | 4 ++-- frontend/vite.config.ts | 10 ++++----- frontend/vitest.config.ts | 12 +++++------ prettier.config.js | 2 +- 14 files changed, 102 insertions(+), 103 deletions(-) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 0777b2e8..bf5fb037 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,10 +1,10 @@ { - "recommendations": [ - "Vue.volar", - "vitest.explorer", - "ms-playwright.playwright", - "dbaeumer.vscode-eslint", - "EditorConfig.EditorConfig", - "esbenp.prettier-vscode" - ] + "recommendations": [ + "Vue.volar", + "vitest.explorer", + "ms-playwright.playwright", + "dbaeumer.vscode-eslint", + "EditorConfig.EditorConfig", + "esbenp.prettier-vscode" + ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 4ae19c08..21550adc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,13 +1,13 @@ { - "explorer.fileNesting.enabled": true, - "explorer.fileNesting.patterns": { - "tsconfig.json": "tsconfig.*.json, env.d.ts", - "vite.config.*": "jsconfig*, vitest.config.*, cypress.config.*, playwright.config.*", - "package.json": "package-lock.json, pnpm*, .yarnrc*, yarn*, .eslint*, eslint*, .prettier*, prettier*, .editorconfig" - }, - "editor.codeActionsOnSave": { - "source.fixAll.eslint": "explicit" - }, - "editor.formatOnSave": false, - "editor.defaultFormatter": "esbenp.prettier-vscode" + "explorer.fileNesting.enabled": true, + "explorer.fileNesting.patterns": { + "tsconfig.json": "tsconfig.*.json, env.d.ts", + "vite.config.*": "jsconfig*, vitest.config.*, cypress.config.*, playwright.config.*", + "package.json": "package-lock.json, pnpm*, .yarnrc*, yarn*, .eslint*, eslint*, .prettier*, prettier*, .editorconfig" + }, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + "editor.formatOnSave": false, + "editor.defaultFormatter": "esbenp.prettier-vscode" } diff --git a/backend/tests/example.test.ts b/backend/tests/example.test.ts index 638d03b1..9904b6d2 100644 --- a/backend/tests/example.test.ts +++ b/backend/tests/example.test.ts @@ -1,9 +1,9 @@ -import { describe, it, expect } from "vitest"; +import { describe, it, expect } from 'vitest'; -describe("Sample test", () => { - it("should sum to 2", () => { +describe('Sample test', () => { + it('should sum to 2', () => { const expected = 2; const result = 1 + 1; expect(result).toBe(expected); }); -}) +}); diff --git a/backend/tsconfig.json b/backend/tsconfig.json index 6cdb459b..86267d25 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -1,8 +1,6 @@ { "extends": "../tsconfig.json", - "include": [ - "src/**/*.ts" - ], + "include": ["src/**/*.ts"], "compilerOptions": { "rootDir": "./src", "outDir": "./dist" diff --git a/docker-compose.yml b/docker-compose.yml index e8efb530..f579b470 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,16 +1,16 @@ services: - db: - image: postgres:latest - environment: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: postgres - ports: - - "5432:5432" - network_mode: "host" - volumes: - - postgres_data:/var/lib/postgresql/data - - ./backend/config/db/init.sql:/docker-entrypoint-initdb.d/init.sql + db: + image: postgres:latest + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + - '5432:5432' + network_mode: 'host' + volumes: + - postgres_data:/var/lib/postgresql/data + - ./backend/config/db/init.sql:/docker-entrypoint-initdb.d/init.sql volumes: postgres_data: diff --git a/eslint.config.ts b/eslint.config.ts index 7e0ec525..b838d8c5 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -16,13 +16,13 @@ export default [ prettierConfig, includeIgnoreFile(gitignorePath), { - ignores: ['**/dist/**', '**/.node_modules/**', '**/coverage/**', '**/.github/**'], - files: [ - "**/*.ts", - "**/*.cts", - "**.*.mts", - "**/*.ts" - ] + ignores: [ + '**/dist/**', + '**/.node_modules/**', + '**/coverage/**', + '**/.github/**', + ], + files: ['**/*.ts', '**/*.cts', '**.*.mts', '**/*.ts'], }, { languageOptions: { diff --git a/frontend/e2e/vue.spec.ts b/frontend/e2e/vue.spec.ts index 9471698e..fd4797b7 100644 --- a/frontend/e2e/vue.spec.ts +++ b/frontend/e2e/vue.spec.ts @@ -1,8 +1,8 @@ -import { test, expect } from '@playwright/test'; +import { test, expect } from "@playwright/test"; // See here how to get started: // https://playwright.dev/docs/intro -test('visits the app root url', async ({ page }) => { - await page.goto('/'); - await expect(page.locator('h1')).toHaveText('You did it!'); +test("visits the app root url", async ({ page }) => { + await page.goto("/"); + await expect(page.locator("h1")).toHaveText("You did it!"); }); diff --git a/frontend/eslint.config.ts b/frontend/eslint.config.ts index 216bb5c1..9e68e9c0 100644 --- a/frontend/eslint.config.ts +++ b/frontend/eslint.config.ts @@ -1,12 +1,9 @@ -import pluginVue from 'eslint-plugin-vue'; -import { - defineConfigWithVueTs, - vueTsConfigs, -} from '@vue/eslint-config-typescript'; -import pluginVitest from '@vitest/eslint-plugin'; -import pluginPlaywright from 'eslint-plugin-playwright'; -import skipFormatting from '@vue/eslint-config-prettier/skip-formatting'; -import rootConfig from '../eslint.config'; +import pluginVue from "eslint-plugin-vue"; +import { defineConfigWithVueTs, vueTsConfigs } from "@vue/eslint-config-typescript"; +import pluginVitest from "@vitest/eslint-plugin"; +import pluginPlaywright from "eslint-plugin-playwright"; +import skipFormatting from "@vue/eslint-config-prettier/skip-formatting"; +import rootConfig from "../eslint.config"; // To allow more languages other than `ts` in `.vue` files, uncomment the following lines: // Import { configureVueProject } from '@vue/eslint-config-typescript' @@ -15,31 +12,28 @@ import rootConfig from '../eslint.config'; const vueConfig = defineConfigWithVueTs( { - name: 'app/files-to-lint', - files: ['**/*.{ts,mts,tsx,vue}'], + name: "app/files-to-lint", + files: ["**/*.{ts,mts,tsx,vue}"], }, { - name: 'app/files-to-ignore', - ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + name: "app/files-to-ignore", + ignores: ["**/dist/**", "**/dist-ssr/**", "**/coverage/**"], }, - pluginVue.configs['flat/essential'], + pluginVue.configs["flat/essential"], vueTsConfigs.recommended, { ...pluginVitest.configs.recommended, - files: ['src/**/__tests__/*'], + files: ["src/**/__tests__/*"], }, { - ...pluginPlaywright.configs['flat/recommended'], - files: ['e2e/**/*.{test,spec}.{js,ts,jsx,tsx}'], + ...pluginPlaywright.configs["flat/recommended"], + files: ["e2e/**/*.{test,spec}.{js,ts,jsx,tsx}"], }, - skipFormatting + skipFormatting, ); -export default [ - ...rootConfig, - ...vueConfig -] +export default [...rootConfig, ...vueConfig]; diff --git a/frontend/index.html b/frontend/index.html index a678cb53..3c1f2f07 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -2,12 +2,21 @@ - - + + Vite App
- + diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts index a6cfb499..06d60d89 100644 --- a/frontend/playwright.config.ts +++ b/frontend/playwright.config.ts @@ -1,5 +1,5 @@ -import process from 'node:process'; -import { defineConfig, devices } from '@playwright/test'; +import process from "node:process"; +import { defineConfig, devices } from "@playwright/test"; /** * Read environment variables from file. @@ -11,7 +11,7 @@ import { defineConfig, devices } from '@playwright/test'; * See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ - testDir: './e2e', + testDir: "./e2e", /* Maximum time one test can run for. */ timeout: 30 * 1000, expect: { @@ -28,18 +28,16 @@ export default defineConfig({ /* Opt out of parallel tests on CI. */ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: 'html', + reporter: "html", /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ actionTimeout: 0, /* Base URL to use in actions like `await page.goto('/')`. */ - baseURL: process.env.CI - ? 'http://localhost:4173' - : 'http://localhost:5173', + baseURL: process.env.CI ? "http://localhost:4173" : "http://localhost:5173", /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on-first-retry', + trace: "on-first-retry", /* Only on CI systems run the tests headless */ headless: Boolean(process.env.CI), @@ -48,21 +46,21 @@ export default defineConfig({ /* Configure projects for major browsers */ projects: [ { - name: 'chromium', + name: "chromium", use: { - ...devices['Desktop Chrome'], + ...devices["Desktop Chrome"], }, }, { - name: 'firefox', + name: "firefox", use: { - ...devices['Desktop Firefox'], + ...devices["Desktop Firefox"], }, }, { - name: 'webkit', + name: "webkit", use: { - ...devices['Desktop Safari'], + ...devices["Desktop Safari"], }, }, @@ -105,7 +103,7 @@ export default defineConfig({ * Use the preview server on CI for more realistic testing. * Playwright will re-use the local server if there is already a dev-server running. */ - command: process.env.CI ? 'npm run preview' : 'npm run dev', + command: process.env.CI ? "npm run preview" : "npm run dev", port: process.env.CI ? 4173 : 5173, reuseExistingServer: !process.env.CI, }, diff --git a/frontend/prettier.config.js b/frontend/prettier.config.js index 00145504..4bc9699b 100644 --- a/frontend/prettier.config.js +++ b/frontend/prettier.config.js @@ -2,10 +2,10 @@ * @type {import("prettier").Options} */ -const rootConfig = import ('../prettier.config.js'); +const rootConfig = import("../prettier.config.js"); export default { ...rootConfig, vueIndentScriptAndStyle: true, - singleAttributePerLine: true + singleAttributePerLine: true, }; diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index a558039c..7bb3e1c6 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,15 +1,15 @@ -import { fileURLToPath, URL } from 'node:url'; +import { fileURLToPath, URL } from "node:url"; -import { defineConfig } from 'vite'; -import vue from '@vitejs/plugin-vue'; -import vueDevTools from 'vite-plugin-vue-devtools'; +import { defineConfig } from "vite"; +import vue from "@vitejs/plugin-vue"; +import vueDevTools from "vite-plugin-vue-devtools"; // https://vite.dev/config/ export default defineConfig({ plugins: [vue(), vueDevTools()], resolve: { alias: { - '@': fileURLToPath(new URL('./src', import.meta.url)), + "@": fileURLToPath(new URL("./src", import.meta.url)), }, }, }); diff --git a/frontend/vitest.config.ts b/frontend/vitest.config.ts index 176ad62e..ba2d72b6 100644 --- a/frontend/vitest.config.ts +++ b/frontend/vitest.config.ts @@ -1,14 +1,14 @@ -import { fileURLToPath } from 'node:url'; -import { mergeConfig, defineConfig, configDefaults } from 'vitest/config'; -import viteConfig from './vite.config'; +import { fileURLToPath } from "node:url"; +import { mergeConfig, defineConfig, configDefaults } from "vitest/config"; +import viteConfig from "./vite.config"; export default mergeConfig( viteConfig, defineConfig({ test: { - environment: 'jsdom', - exclude: [...configDefaults.exclude, 'e2e/**'], - root: fileURLToPath(new URL('./', import.meta.url)), + environment: "jsdom", + exclude: [...configDefaults.exclude, "e2e/**"], + root: fileURLToPath(new URL("./", import.meta.url)), }, }), ); diff --git a/prettier.config.js b/prettier.config.js index f78ee017..8be1cdc4 100644 --- a/prettier.config.js +++ b/prettier.config.js @@ -10,4 +10,4 @@ export default { objectWrap: 'preserve', bracketSameLine: false, arrowParens: 'always', -} +}; From 50ccf00777583a92f60b3e61b74251d6f5a5f4ec Mon Sep 17 00:00:00 2001 From: Timo De Meyst Date: Fri, 28 Feb 2025 21:13:26 +0100 Subject: [PATCH 015/180] test: test lint-action (wordt gerevert) --- test.ts | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 test.ts diff --git a/test.ts b/test.ts new file mode 100644 index 00000000..c9da7bdd --- /dev/null +++ b/test.ts @@ -0,0 +1,9 @@ +async function test_Function() { + return 1+1; +} + +for (let index = 0; index < 100; index++) { + await test_Function(); + let a = "test"; +} + From 5ffaf090d0a2ac92444d8e80235806622cc07570 Mon Sep 17 00:00:00 2001 From: Lint Action Date: Fri, 28 Feb 2025 20:14:38 +0000 Subject: [PATCH 016/180] style: fix linting issues met lint-action --- test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.ts b/test.ts index c9da7bdd..5b6d755b 100644 --- a/test.ts +++ b/test.ts @@ -4,6 +4,6 @@ async function test_Function() { for (let index = 0; index < 100; index++) { await test_Function(); - let a = "test"; + const a = "test"; } From 6e0f527b1f9df07a8a57bbb314a4e2edaf4c8028 Mon Sep 17 00:00:00 2001 From: Lint Action Date: Fri, 28 Feb 2025 20:14:41 +0000 Subject: [PATCH 017/180] style: fix linting issues met lint-action --- test.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test.ts b/test.ts index 5b6d755b..00b168ab 100644 --- a/test.ts +++ b/test.ts @@ -1,9 +1,8 @@ async function test_Function() { - return 1+1; + return 1 + 1; } for (let index = 0; index < 100; index++) { - await test_Function(); - const a = "test"; + await test_Function(); + const a = 'test'; } - From ccbdd9bce4ec4ab310e62d109256beeb8debfbbb Mon Sep 17 00:00:00 2001 From: Timo De Meyst Date: Fri, 28 Feb 2025 21:18:29 +0100 Subject: [PATCH 018/180] Revert "test: test lint-action (wordt gerevert)" This reverts commit 50ccf00777583a92f60b3e61b74251d6f5a5f4ec. --- test.ts | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 test.ts diff --git a/test.ts b/test.ts deleted file mode 100644 index 00b168ab..00000000 --- a/test.ts +++ /dev/null @@ -1,8 +0,0 @@ -async function test_Function() { - return 1 + 1; -} - -for (let index = 0; index < 100; index++) { - await test_Function(); - const a = 'test'; -} From e5e39e5cea07d6434ba0c3344aa6b0a45d9a9563 Mon Sep 17 00:00:00 2001 From: Timo De Meyst Date: Fri, 28 Feb 2025 21:26:58 +0100 Subject: [PATCH 019/180] chore: wordt enkel uitgevoerd in de dev branch --- .github/workflows/lint-action.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/lint-action.yml b/.github/workflows/lint-action.yml index 98bfa848..5540fbad 100644 --- a/.github/workflows/lint-action.yml +++ b/.github/workflows/lint-action.yml @@ -4,6 +4,8 @@ on: # Trigger the workflow on push or pull request, # but only for the main branch push: + branches: + - dev # Replace pull_request with pull_request_target if you # plan to use this action with forks, see the Limitations section pull_request: From 9aa0b25c73c84593127311b4e1d84071dfe32f41 Mon Sep 17 00:00:00 2001 From: Timo De Meyst Date: Sat, 1 Mar 2025 11:07:07 +0100 Subject: [PATCH 020/180] chore: update commit message van lint-action lint-action commits zeggen nu welke linter de aanpassingen heeft gemaakt --- .github/workflows/lint-action.yml | 66 +++++++++++++++---------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/.github/workflows/lint-action.yml b/.github/workflows/lint-action.yml index 5540fbad..e0f24ba9 100644 --- a/.github/workflows/lint-action.yml +++ b/.github/workflows/lint-action.yml @@ -1,45 +1,45 @@ name: Lint on: - # Trigger the workflow on push or pull request, - # but only for the main branch - push: - branches: - - dev - # Replace pull_request with pull_request_target if you - # plan to use this action with forks, see the Limitations section - pull_request: - branches: - - dev + # Trigger the workflow on push or pull request, + # but only for the main branch + push: + branches: + - dev + # Replace pull_request with pull_request_target if you + # plan to use this action with forks, see the Limitations section + pull_request: + branches: + - dev # Down scope as necessary via https://docs.github.com/en/actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token permissions: - checks: write - contents: write + checks: write + contents: write jobs: - run-linters: - name: Run linters - runs-on: [self-hosted, Linux, X64] + run-linters: + name: Run linters + runs-on: [self-hosted, Linux, X64] - steps: - - name: Check out Git repository - uses: actions/checkout@v4 + steps: + - name: Check out Git repository + uses: actions/checkout@v4 - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: 20 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 - # ESLint and Prettier must be in `package.json` - - name: Install Node.js dependencies - run: npm ci + # ESLint and Prettier must be in `package.json` + - name: Install Node.js dependencies + run: npm ci - - name: Run linters - uses: rkuykendall/lint-action@master - with: - auto_fix: true - eslint: true - eslint_args: "--config eslint.config.ts" - prettier: true - commit_message: "style: fix linting issues met lint-action" \ No newline at end of file + - name: Run linters + uses: rkuykendall/lint-action@master + with: + auto_fix: true + eslint: true + eslint_args: '--config eslint.config.ts' + prettier: true + commit_message: 'style: fix linting issues met ${linter}' From 81bbe84dfd3802b9c95e3b13a7ac47204d40f512 Mon Sep 17 00:00:00 2001 From: Timo De Meyst Date: Sat, 1 Mar 2025 11:32:58 +0100 Subject: [PATCH 021/180] fix: update package-lock.json --- package-lock.json | 4002 ++++++++++++++++----------------------------- 1 file changed, 1388 insertions(+), 2614 deletions(-) diff --git a/package-lock.json b/package-lock.json index 65b94c8d..2cbd1995 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,11 +36,11 @@ "@mikro-orm/postgresql": "6.4.6", "@mikro-orm/reflection": "6.4.6", "@mikro-orm/sqlite": "6.4.6", + "@types/js-yaml": "^4.0.9", "dotenv": "^16.4.7", "express": "^5.0.1", - "uuid": "^11.1.0", "js-yaml": "^4.1.0", - "@types/js-yaml": "^4.0.9", + "uuid": "^11.1.0" }, "devDependencies": { "@mikro-orm/cli": "^6.4.6", @@ -53,27 +53,210 @@ "vitest": "^3.0.6" } }, - "backend/node_modules/@mikro-orm/sqlite": { - "version": "6.4.6", - "resolved": "https://registry.npmjs.org/@mikro-orm/sqlite/-/sqlite-6.4.6.tgz", - "integrity": "sha512-BvoLd6qge2N4P2w9yjPP8+Ya5dxxnZrS6W3B2xm0m8BUesWnaCg2pmGXQpzFjrpYMg40mZ+RJWRTPq4M2Nl4lw==", + "backend/node_modules/accepts": { + "version": "2.0.0", + "license": "MIT", "dependencies": { - "@mikro-orm/knex": "6.4.6", - "fs-extra": "11.3.0", - "sqlite3": "5.1.7", - "sqlstring-sqlite": "0.1.1" + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" }, "engines": { - "node": ">= 18.12.0" + "node": ">= 0.6" + } + }, + "backend/node_modules/body-parser": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.5.2", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" }, - "peerDependencies": { - "@mikro-orm/core": "^6.0.0" + "engines": { + "node": ">=18" + } + }, + "backend/node_modules/body-parser/node_modules/qs": { + "version": "6.14.0", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "backend/node_modules/bytes": { + "version": "3.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "backend/node_modules/content-disposition": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "backend/node_modules/content-type": { + "version": "1.0.5", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "backend/node_modules/cookie": { + "version": "0.7.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "backend/node_modules/cookie-signature": { + "version": "1.2.2", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "backend/node_modules/depd": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "backend/node_modules/encodeurl": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "backend/node_modules/escape-html": { + "version": "1.0.3", + "license": "MIT" + }, + "backend/node_modules/etag": { + "version": "1.8.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "backend/node_modules/express": { + "version": "5.0.1", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.0.1", + "content-disposition": "^1.0.0", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "^1.2.1", + "debug": "4.3.6", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "^2.0.0", + "fresh": "2.0.0", + "http-errors": "2.0.0", + "merge-descriptors": "^2.0.0", + "methods": "~1.1.2", + "mime-types": "^3.0.0", + "on-finished": "2.4.1", + "once": "1.4.0", + "parseurl": "~1.3.3", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "router": "^2.0.0", + "safe-buffer": "5.2.1", + "send": "^1.1.0", + "serve-static": "^2.1.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "^2.0.0", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "backend/node_modules/express/node_modules/debug": { + "version": "4.3.6", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "backend/node_modules/finalhandler": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "backend/node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "backend/node_modules/finalhandler/node_modules/encodeurl": { + "version": "1.0.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "backend/node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "backend/node_modules/fresh": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, "backend/node_modules/globals": { "version": "15.15.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", - "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", "dev": true, "license": "MIT", "engines": { @@ -83,6 +266,75 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "backend/node_modules/http-errors": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "backend/node_modules/iconv-lite": { + "version": "0.5.2", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "backend/node_modules/merge-descriptors": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "backend/node_modules/methods": { + "version": "1.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "backend/node_modules/mime-db": { + "version": "1.53.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "backend/node_modules/mime-types": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "mime-db": "^1.53.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "backend/node_modules/ms": { + "version": "2.1.2", + "license": "MIT" + }, + "backend/node_modules/negotiator": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "frontend": { "name": "dwengo-1-frontend", "version": "0.0.1", @@ -114,12 +366,368 @@ "vue-tsc": "^2.2.2" } }, + "frontend/node_modules/agent-base": { + "version": "7.1.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "frontend/node_modules/asynckit": { + "version": "0.4.0", + "dev": true, + "license": "MIT" + }, + "frontend/node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "frontend/node_modules/combined-stream": { + "version": "1.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "frontend/node_modules/cssstyle": { + "version": "4.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^2.8.2", + "rrweb-cssom": "^0.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "frontend/node_modules/data-urls": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "frontend/node_modules/decimal.js": { + "version": "10.5.0", + "dev": true, + "license": "MIT" + }, + "frontend/node_modules/delayed-stream": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "frontend/node_modules/dunder-proto": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "frontend/node_modules/es-define-property": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "frontend/node_modules/es-errors": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "frontend/node_modules/es-object-atoms": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "frontend/node_modules/es-set-tostringtag": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "frontend/node_modules/eslint-plugin-playwright": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "workspaces": [ + "examples" + ], + "dependencies": { + "globals": "^13.23.0" + }, + "engines": { + "node": ">=16.6.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "frontend/node_modules/form-data": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "frontend/node_modules/get-intrinsic": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "frontend/node_modules/get-proto": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "frontend/node_modules/globals": { + "version": "13.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "frontend/node_modules/gopd": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "frontend/node_modules/has-symbols": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "frontend/node_modules/has-tostringtag": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "frontend/node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "frontend/node_modules/http-proxy-agent": { + "version": "7.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "frontend/node_modules/https-proxy-agent": { + "version": "7.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "frontend/node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "frontend/node_modules/jsdom": { + "version": "26.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "cssstyle": "^4.2.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.1", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.16", + "parse5": "^7.2.1", + "rrweb-cssom": "^0.8.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.1.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "frontend/node_modules/jsdom/node_modules/xml-name-validator": { + "version": "5.0.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "frontend/node_modules/math-intrinsics": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "frontend/node_modules/mime-db": { + "version": "1.52.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "frontend/node_modules/mime-types": { + "version": "2.1.35", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -133,7 +741,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -144,31 +751,15 @@ "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz", "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/antfu" } }, - "node_modules/@asamuzakjp/css-color": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-2.8.3.tgz", - "integrity": "sha512-GIc76d9UI1hCvOATjZPyHFmE5qhRccp3/zGfMPapK3jBi+yocEzp6BBB0UnfRYP9NP4FANqUZYb0hnfs3TM3hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@csstools/css-calc": "^2.1.1", - "@csstools/css-color-parser": "^3.0.7", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "lru-cache": "^10.4.3" - } - }, "node_modules/@babel/code-frame": { "version": "7.26.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", @@ -183,7 +774,6 @@ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -193,7 +783,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.9.tgz", "integrity": "sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", @@ -224,7 +813,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -234,7 +822,6 @@ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.9.tgz", "integrity": "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/parser": "^7.26.9", "@babel/types": "^7.26.9", @@ -251,7 +838,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -262,7 +848,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.25.9" }, @@ -275,7 +860,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/compat-data": "^7.26.5", "@babel/helper-validator-option": "^7.25.9", @@ -292,7 +876,6 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, - "license": "ISC", "dependencies": { "yallist": "^3.0.2" } @@ -302,17 +885,21 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, "node_modules/@babel/helper-create-class-features-plugin": { "version": "7.26.9", "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.26.9.tgz", "integrity": "sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-member-expression-to-functions": "^7.25.9", @@ -334,7 +921,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -344,7 +930,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" @@ -358,7 +943,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" @@ -372,7 +956,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9", @@ -390,7 +973,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.25.9" }, @@ -403,7 +985,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -413,7 +994,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz", "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-member-expression-to-functions": "^7.25.9", "@babel/helper-optimise-call-expression": "^7.25.9", @@ -431,7 +1011,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" @@ -444,7 +1023,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -453,7 +1031,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -463,7 +1040,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -473,7 +1049,6 @@ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.9.tgz", "integrity": "sha512-Mz/4+y8udxBKdmzt/UjPACs4G3j5SshJJEFFKxlCGPydG4JAHXxjWjAwjd09tf6oINvl1VfMJo+nB7H2YKQ0dA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/template": "^7.26.9", "@babel/types": "^7.26.9" @@ -486,7 +1061,6 @@ "version": "7.26.9", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz", "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==", - "license": "MIT", "dependencies": { "@babel/types": "^7.26.9" }, @@ -502,7 +1076,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.25.9.tgz", "integrity": "sha512-smkNLL/O1ezy9Nhy4CNosc4Va+1wo5w4gzSZeLe6y6dM4mmHfYOCPolXQPHQxonZCF+ZyebxN9vqOolkYrSn5g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", @@ -520,7 +1093,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.25.9.tgz", "integrity": "sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, @@ -536,7 +1108,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, @@ -552,7 +1123,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -565,7 +1135,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, @@ -581,7 +1150,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, @@ -597,7 +1165,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.8.tgz", "integrity": "sha512-bME5J9AC8ChwA7aEPJ6zym3w7aObZULHhbNLU0bKUhKsAkylkzUdq+0kdymh9rzi8nlNFl2bmldFBCKNJBUpuw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-create-class-features-plugin": "^7.25.9", @@ -617,7 +1184,6 @@ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/parser": "^7.26.9", @@ -632,7 +1198,6 @@ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.9.tgz", "integrity": "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.26.9", @@ -651,7 +1216,6 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } @@ -660,7 +1224,6 @@ "version": "7.26.9", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz", "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==", - "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" @@ -674,7 +1237,6 @@ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -682,121 +1244,6 @@ "node": ">=12" } }, - "node_modules/@csstools/color-helpers": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.1.tgz", - "integrity": "sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - } - }, - "node_modules/@csstools/css-calc": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.1.tgz", - "integrity": "sha512-rL7kaUnTkL9K+Cvo2pnCieqNpTKgQzy5f+N+5Iuko9HAoasP+xgprVh7KN/MaJVvVL1l0EzQq2MoqBHKSrDrag==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3" - } - }, - "node_modules/@csstools/css-color-parser": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.7.tgz", - "integrity": "sha512-nkMp2mTICw32uE5NN+EsJ4f5N+IGFeCFu4bGpiKgb2Pq/7J/MpyLBeQ5ry4KKtRFZaYs6sTmcMYrSRIyj5DFKA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "dependencies": { - "@csstools/color-helpers": "^5.0.1", - "@csstools/css-calc": "^2.1.1" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3" - } - }, - "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", - "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.3" - } - }, - "node_modules/@csstools/css-tokenizer": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz", - "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.0", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", @@ -805,7 +1252,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "aix" @@ -822,7 +1268,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -839,7 +1284,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -856,7 +1300,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -873,7 +1316,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -890,7 +1332,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -907,7 +1348,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -924,7 +1364,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -941,7 +1380,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -958,7 +1396,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -975,7 +1412,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -992,7 +1428,6 @@ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -1009,7 +1444,6 @@ "mips64el" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -1026,7 +1460,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -1043,7 +1476,6 @@ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -1060,7 +1492,6 @@ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -1077,7 +1508,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -1094,7 +1524,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "netbsd" @@ -1111,7 +1540,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "netbsd" @@ -1128,7 +1556,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -1145,7 +1572,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -1162,7 +1588,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "sunos" @@ -1179,7 +1604,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -1196,7 +1620,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -1213,7 +1636,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -1227,7 +1649,6 @@ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", "dev": true, - "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.4.3" }, @@ -1246,17 +1667,15 @@ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, - "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/compat": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.6.tgz", - "integrity": "sha512-k7HNCqApoDHM6XzT30zGoETj+D+uUcZUb+IVAJmar3u6bvHf7hhHJcWx09QHj4/a2qrKZMWU0E16tvkiAdv06Q==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.7.tgz", + "integrity": "sha512-xvv7hJE32yhegJ8xNAnb62ggiAwTYHBpUCWhRxEj/ksvgDJuSXfoDkBcRYaYNFiJ+jH0IE3K16hd+xXzhBgNbg==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -1274,7 +1693,6 @@ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", @@ -1289,7 +1707,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1300,7 +1717,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1309,11 +1725,10 @@ } }, "node_modules/@eslint/core": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.11.0.tgz", - "integrity": "sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", + "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" }, @@ -1322,11 +1737,10 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", - "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz", + "integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==", "dev": true, - "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -1350,7 +1764,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1361,7 +1774,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1370,11 +1782,10 @@ } }, "node_modules/@eslint/js": { - "version": "9.20.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.20.0.tgz", - "integrity": "sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==", + "version": "9.21.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.21.0.tgz", + "integrity": "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==", "dev": true, - "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -1384,19 +1795,17 @@ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.6.tgz", - "integrity": "sha512-+0TjwR1eAUdZtvv/ir1mGX+v0tUoR3VEPB8Up0LLJC+whRW0GgBBtpbOkg/a/U4Dxa6l5a3l9AJ1aWIQVyoWJA==", + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz", + "integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.11.0", + "@eslint/core": "^0.12.0", "levn": "^0.4.1" }, "engines": { @@ -1414,7 +1823,6 @@ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=18.18.0" } @@ -1424,7 +1832,6 @@ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" @@ -1438,7 +1845,6 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=18.18" }, @@ -1452,7 +1858,6 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -1466,7 +1871,6 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=18.18" }, @@ -1479,7 +1883,6 @@ "version": "10.0.5", "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-10.0.5.tgz", "integrity": "sha512-F3snDTQs0MdvnnyzTDTVkOYVAZOE/MHwRvF7mn7Jw1yuih4NrFYLNYIymGlLmq4HU2iIdzYsZ7f47bOcwY73XQ==", - "license": "MIT", "dependencies": { "@intlify/message-compiler": "10.0.5", "@intlify/shared": "10.0.5" @@ -1495,7 +1898,6 @@ "version": "10.0.5", "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-10.0.5.tgz", "integrity": "sha512-6GT1BJ852gZ0gItNZN2krX5QAmea+cmdjMvsWohArAZ3GmHdnNANEcF9JjPXAMRtQ6Ux5E269ymamg/+WU6tQA==", - "license": "MIT", "dependencies": { "@intlify/shared": "10.0.5", "source-map-js": "^1.0.2" @@ -1511,7 +1913,6 @@ "version": "10.0.5", "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-10.0.5.tgz", "integrity": "sha512-bmsP4L2HqBF6i6uaMqJMcFBONVjKt+siGluRq4Ca4C0q7W2eMaVZr8iCgF9dKbcVXutftkC7D6z2SaSMmLiDyA==", - "license": "MIT", "engines": { "node": ">= 16" }, @@ -1524,7 +1925,6 @@ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, - "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -1537,97 +1937,11 @@ "node": ">=12" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@jercle/yargonaut": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/@jercle/yargonaut/-/yargonaut-1.1.5.tgz", "integrity": "sha512-zBp2myVvBHp1UaJsNTyS6q4UDKT7eRiqTS4oNTS6VQMd6mpxYOdbeK4pY279cDCdakGy6hG0J3ejoXZVsPwHqw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "chalk": "^4.1.2", "figlet": "^1.5.2", @@ -1639,7 +1953,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -1654,7 +1967,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -1665,7 +1977,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -1675,7 +1986,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -1683,30 +1993,27 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "license": "MIT" + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "node_modules/@mikro-orm/cli": { - "version": "6.4.6", - "resolved": "https://registry.npmjs.org/@mikro-orm/cli/-/cli-6.4.6.tgz", - "integrity": "sha512-sTMoDSJrnHZBT+ZAG40OeZwR9zRTYHtaaub9OoMM2CrxfI1KeiNqL/XFB4LaM5SVRAbnoEFpMJwQ8KS+5NcN9w==", + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/@mikro-orm/cli/-/cli-6.4.7.tgz", + "integrity": "sha512-jaEm8olUP7h/kz4AZyu21TJ8P1qAGgdyvFYG+J5eGAtPsdMN8ZMQJJy2m6DZcHNbuyllCVdzp3XT6MAzG+uwMw==", "dev": true, - "license": "MIT", "dependencies": { "@jercle/yargonaut": "1.1.5", - "@mikro-orm/core": "6.4.6", - "@mikro-orm/knex": "6.4.6", + "@mikro-orm/core": "6.4.7", + "@mikro-orm/knex": "6.4.7", "fs-extra": "11.3.0", "tsconfig-paths": "4.2.0", "yargs": "17.7.2" @@ -1719,11 +2026,40 @@ "node": ">= 18.12.0" } }, + "node_modules/@mikro-orm/cli/node_modules/@mikro-orm/core": { + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-6.4.7.tgz", + "integrity": "sha512-ZePm7IRpW6/tGC6axCezI1/5YA3+MiDsbEj5KHgXDIxzHnftVfL3nbYlPlr0pW/UQSL5QcRqXxHIQz4P2OlFhg==", + "dev": true, + "dependencies": { + "dataloader": "2.2.3", + "dotenv": "16.4.7", + "esprima": "4.0.1", + "fs-extra": "11.3.0", + "globby": "11.1.0", + "mikro-orm": "6.4.7", + "reflect-metadata": "0.2.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/b4nan" + } + }, + "node_modules/@mikro-orm/cli/node_modules/mikro-orm": { + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-6.4.7.tgz", + "integrity": "sha512-lRB92yekDcdQEHloNY9LWfNLyKd3WajxPSe3jBvyVR9gMIO7YsjhqxL0mYvoQi8MQzXcUTi1EkWG05IM3gidIw==", + "dev": true, + "engines": { + "node": ">= 18.12.0" + } + }, "node_modules/@mikro-orm/core": { "version": "6.4.6", "resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-6.4.6.tgz", "integrity": "sha512-xVm/ALG/3vTMgh6SrvojJ6jjMa0s2hNzWN0triDB16BaNdLwWE4aAaAe+3CuoMFqJAArSOUISTEjExbzELB1ZA==", - "license": "MIT", "dependencies": { "dataloader": "2.2.3", "dotenv": "16.4.7", @@ -1741,10 +2077,10 @@ } }, "node_modules/@mikro-orm/knex": { - "version": "6.4.6", - "resolved": "https://registry.npmjs.org/@mikro-orm/knex/-/knex-6.4.6.tgz", - "integrity": "sha512-o6t67tFH/GuPZCCEtKbTTL8HDXNgB2ITjButCTZLwteL0qI9yE/f7K6K+dEUKW+hAL3KRvc2BQeumvCVWFeISg==", - "license": "MIT", + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/@mikro-orm/knex/-/knex-6.4.7.tgz", + "integrity": "sha512-IH2imlCzEzPyjMGmAn/9yEP4wRxKHczCiPfI7GWAVI2dRToox1MFpQzBW1x/m+3Dvwz8jXVakHVANN7KPZBi5w==", + "dev": true, "dependencies": { "fs-extra": "11.3.0", "knex": "3.1.0", @@ -1775,7 +2111,6 @@ "version": "6.4.6", "resolved": "https://registry.npmjs.org/@mikro-orm/postgresql/-/postgresql-6.4.6.tgz", "integrity": "sha512-ZcuGp6n/SPzkHPANksjdLPyeu6jT7WCg3ueNViVrxdsguCi+/grz4I+hbOQDXV8uNHCAUOw6+WP2ndcVEYkZZQ==", - "license": "MIT", "dependencies": { "@mikro-orm/knex": "6.4.6", "pg": "8.13.2", @@ -1790,11 +2125,40 @@ "@mikro-orm/core": "^6.0.0" } }, + "node_modules/@mikro-orm/postgresql/node_modules/@mikro-orm/knex": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/@mikro-orm/knex/-/knex-6.4.6.tgz", + "integrity": "sha512-o6t67tFH/GuPZCCEtKbTTL8HDXNgB2ITjButCTZLwteL0qI9yE/f7K6K+dEUKW+hAL3KRvc2BQeumvCVWFeISg==", + "dependencies": { + "fs-extra": "11.3.0", + "knex": "3.1.0", + "sqlstring": "2.3.3" + }, + "engines": { + "node": ">= 18.12.0" + }, + "peerDependencies": { + "@mikro-orm/core": "^6.0.0", + "better-sqlite3": "*", + "libsql": "*", + "mariadb": "*" + }, + "peerDependenciesMeta": { + "better-sqlite3": { + "optional": true + }, + "libsql": { + "optional": true + }, + "mariadb": { + "optional": true + } + } + }, "node_modules/@mikro-orm/reflection": { "version": "6.4.6", "resolved": "https://registry.npmjs.org/@mikro-orm/reflection/-/reflection-6.4.6.tgz", "integrity": "sha512-7mL7HFVnaOOhDNgLjjndWyeJUtOl2wKn0spSqB8uRjS4XtwNEGVZNkW5YD1t/x7TJ99wUhe+oRDiySciiJSeBQ==", - "license": "MIT", "dependencies": { "globby": "11.1.0", "ts-morph": "25.0.1" @@ -1806,11 +2170,57 @@ "@mikro-orm/core": "^6.0.0" } }, + "node_modules/@mikro-orm/sqlite": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/@mikro-orm/sqlite/-/sqlite-6.4.6.tgz", + "integrity": "sha512-BvoLd6qge2N4P2w9yjPP8+Ya5dxxnZrS6W3B2xm0m8BUesWnaCg2pmGXQpzFjrpYMg40mZ+RJWRTPq4M2Nl4lw==", + "dependencies": { + "@mikro-orm/knex": "6.4.6", + "fs-extra": "11.3.0", + "sqlite3": "5.1.7", + "sqlstring-sqlite": "0.1.1" + }, + "engines": { + "node": ">= 18.12.0" + }, + "peerDependencies": { + "@mikro-orm/core": "^6.0.0" + } + }, + "node_modules/@mikro-orm/sqlite/node_modules/@mikro-orm/knex": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/@mikro-orm/knex/-/knex-6.4.6.tgz", + "integrity": "sha512-o6t67tFH/GuPZCCEtKbTTL8HDXNgB2ITjButCTZLwteL0qI9yE/f7K6K+dEUKW+hAL3KRvc2BQeumvCVWFeISg==", + "dependencies": { + "fs-extra": "11.3.0", + "knex": "3.1.0", + "sqlstring": "2.3.3" + }, + "engines": { + "node": ">= 18.12.0" + }, + "peerDependencies": { + "@mikro-orm/core": "^6.0.0", + "better-sqlite3": "*", + "libsql": "*", + "mariadb": "*" + }, + "peerDependenciesMeta": { + "better-sqlite3": { + "optional": true + }, + "libsql": { + "optional": true + }, + "mariadb": { + "optional": true + } + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -1823,7 +2233,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "license": "MIT", "engines": { "node": ">= 8" } @@ -1832,7 +2241,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -1869,15 +2277,13 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, - "license": "MIT", "optional": true, "engines": { "node": ">=14" @@ -1888,7 +2294,6 @@ "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", "dev": true, - "license": "MIT", "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, @@ -1901,7 +2306,6 @@ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.50.1.tgz", "integrity": "sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==", "dev": true, - "license": "Apache-2.0", "dependencies": { "playwright": "1.50.1" }, @@ -1916,15 +2320,13 @@ "version": "1.0.0-next.28", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@rollup/pluginutils": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", @@ -1942,19 +2344,11 @@ } } }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT" - }, "node_modules/@rollup/pluginutils/node_modules/picomatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -1963,266 +2357,247 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz", - "integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.9.tgz", + "integrity": "sha512-qZdlImWXur0CFakn2BJ2znJOdqYZKiedEPEVNTBrpfPjc/YuTGcaYZcdmNFTkUj3DU0ZM/AElcM8Ybww3xVLzA==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz", - "integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.9.tgz", + "integrity": "sha512-4KW7P53h6HtJf5Y608T1ISKvNIYLWRKMvfnG0c44M6In4DQVU58HZFEVhWINDZKp7FZps98G3gxwC1sb0wXUUg==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz", - "integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.9.tgz", + "integrity": "sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz", - "integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.9.tgz", + "integrity": "sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz", - "integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.9.tgz", + "integrity": "sha512-2lzjQPJbN5UnHm7bHIUKFMulGTQwdvOkouJDpPysJS+QFBGDJqcfh+CxxtG23Ik/9tEvnebQiylYoazFMAgrYw==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz", - "integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.9.tgz", + "integrity": "sha512-SLl0hi2Ah2H7xQYd6Qaiu01kFPzQ+hqvdYSoOtHYg/zCIFs6t8sV95kaoqjzjFwuYQLtOI0RZre/Ke0nPaQV+g==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz", - "integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.9.tgz", + "integrity": "sha512-88I+D3TeKItrw+Y/2ud4Tw0+3CxQ2kLgu3QvrogZ0OfkmX/DEppehus7L3TS2Q4lpB+hYyxhkQiYPJ6Mf5/dPg==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz", - "integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.9.tgz", + "integrity": "sha512-3qyfWljSFHi9zH0KgtEPG4cBXHDFhwD8kwg6xLfHQ0IWuH9crp005GfoUUh/6w9/FWGBwEHg3lxK1iHRN1MFlA==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz", - "integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.9.tgz", + "integrity": "sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz", - "integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.9.tgz", + "integrity": "sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz", - "integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.9.tgz", + "integrity": "sha512-dRAgTfDsn0TE0HI6cmo13hemKpVHOEyeciGtvlBTkpx/F65kTvShtY/EVyZEIfxFkV5JJTuQ9tP5HGBS0hfxIg==", "cpu": [ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz", - "integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.9.tgz", + "integrity": "sha512-PHcNOAEhkoMSQtMf+rJofwisZqaU8iQ8EaSps58f5HYll9EAY5BSErCZ8qBDMVbq88h4UxaNPlbrKqfWP8RfJA==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz", - "integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.9.tgz", + "integrity": "sha512-Z2i0Uy5G96KBYKjeQFKbbsB54xFOL5/y1P5wNBsbXB8yE+At3oh0DVMjQVzCJRJSfReiB2tX8T6HUFZ2k8iaKg==", "cpu": [ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz", - "integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.9.tgz", + "integrity": "sha512-U+5SwTMoeYXoDzJX5dhDTxRltSrIax8KWwfaaYcynuJw8mT33W7oOgz0a+AaXtGuvhzTr2tVKh5UO8GVANTxyQ==", "cpu": [ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz", - "integrity": "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.9.tgz", + "integrity": "sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz", - "integrity": "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.9.tgz", + "integrity": "sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz", - "integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.9.tgz", + "integrity": "sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz", - "integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.9.tgz", + "integrity": "sha512-KB48mPtaoHy1AwDNkAJfHXvHp24H0ryZog28spEs0V48l3H1fr4i37tiyHsgKZJnCmvxsbATdZGBpbmxTE3a9w==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz", - "integrity": "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.9.tgz", + "integrity": "sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -2232,15 +2607,13 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@sindresorhus/merge-streams": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -2261,7 +2634,6 @@ "version": "0.26.1", "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.26.1.tgz", "integrity": "sha512-Sn28TGl/4cFpcM+jwsH1wLncYq3FtN/BIpem+HOygfBWPT5pAeS5dB4VFVzV8FbnOKHpDLZmvAl4AjPEev5idA==", - "license": "MIT", "dependencies": { "fast-glob": "^3.3.2", "minimatch": "^9.0.4", @@ -2272,43 +2644,37 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@tsconfig/node22": { "version": "22.0.0", "resolved": "https://registry.npmjs.org/@tsconfig/node22/-/node22-22.0.0.tgz", "integrity": "sha512-twLQ77zevtxobBOD4ToAtVmuYrpeYUh3qh+TEp+08IWhpsrIflVHqQ1F1CiPxQGL7doCdBIOOCF+1Tm833faNg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/body-parser": { "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dev": true, - "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -2319,7 +2685,6 @@ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -2328,22 +2693,19 @@ "version": "6.11.3", "resolved": "https://registry.npmjs.org/@types/eslint-config-prettier/-/eslint-config-prettier-6.11.3.tgz", "integrity": "sha512-3wXCiM8croUnhg9LdtZUJQwNcQYGWxxdOWDjPe1ykCqJFPVpzAKfs/2dgSoCtAvdPeaponcWPI7mPcGGp9dkKQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/express": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.0.tgz", "integrity": "sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", @@ -2356,7 +2718,6 @@ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz", "integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -2368,21 +2729,18 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/js-yaml": { "version": "4.0.9", "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", - "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", - "license": "MIT" + "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==" }, "node_modules/@types/jsdom": { "version": "21.1.7", "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.7.tgz", "integrity": "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "@types/tough-cookie": "*", @@ -2393,22 +2751,19 @@ "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/node": { - "version": "22.13.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.4.tgz", - "integrity": "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==", + "version": "22.13.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.8.tgz", + "integrity": "sha512-G3EfaZS+iOGYWLLRCEAXdWK9my08oHNZ+FHluRiggIYJPOXzhOiDgpVCUHaUvyIC5/fj7C/p637jdzC666AOKQ==", "dev": true, - "license": "MIT", "dependencies": { "undici-types": "~6.20.0" } @@ -2417,22 +2772,19 @@ "version": "6.9.18", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", "dev": true, - "license": "MIT", "dependencies": { "@types/mime": "^1", "@types/node": "*" @@ -2443,7 +2795,6 @@ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, - "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", @@ -2454,21 +2805,19 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.24.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.1.tgz", - "integrity": "sha512-ll1StnKtBigWIGqvYDVuDmXJHVH4zLVot1yQ4fJtLpL7qacwkxJc1T0bptqw+miBQ/QfUbhl1TcQ4accW5KUyA==", + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.25.0.tgz", + "integrity": "sha512-VM7bpzAe7JO/BFf40pIT1lJqS/z1F8OaSsUB3rpFJucQA4cOSuH2RVVVkFULN+En0Djgr29/jb4EQnedUo95KA==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.24.1", - "@typescript-eslint/type-utils": "8.24.1", - "@typescript-eslint/utils": "8.24.1", - "@typescript-eslint/visitor-keys": "8.24.1", + "@typescript-eslint/scope-manager": "8.25.0", + "@typescript-eslint/type-utils": "8.25.0", + "@typescript-eslint/utils": "8.25.0", + "@typescript-eslint/visitor-keys": "8.25.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -2488,16 +2837,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.24.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.24.1.tgz", - "integrity": "sha512-Tqoa05bu+t5s8CTZFaGpCH2ub3QeT9YDkXbPd3uQ4SfsLoh1/vv2GEYAioPoxCWJJNsenXlC88tRjwoHNts1oQ==", + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.25.0.tgz", + "integrity": "sha512-4gbs64bnbSzu4FpgMiQ1A+D+urxkoJk/kqlDJ2W//5SygaEiAP2B4GoS7TEdxgwol2el03gckFV9lJ4QOMiiHg==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.24.1", - "@typescript-eslint/types": "8.24.1", - "@typescript-eslint/typescript-estree": "8.24.1", - "@typescript-eslint/visitor-keys": "8.24.1", + "@typescript-eslint/scope-manager": "8.25.0", + "@typescript-eslint/types": "8.25.0", + "@typescript-eslint/typescript-estree": "8.25.0", + "@typescript-eslint/visitor-keys": "8.25.0", "debug": "^4.3.4" }, "engines": { @@ -2513,14 +2861,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.24.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.24.1.tgz", - "integrity": "sha512-OdQr6BNBzwRjNEXMQyaGyZzgg7wzjYKfX2ZBV3E04hUCBDv3GQCHiz9RpqdUIiVrMgJGkXm3tcEh4vFSHreS2Q==", + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.25.0.tgz", + "integrity": "sha512-6PPeiKIGbgStEyt4NNXa2ru5pMzQ8OYKO1hX1z53HMomrmiSB+R5FmChgQAP1ro8jMtNawz+TRQo/cSXrauTpg==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.24.1", - "@typescript-eslint/visitor-keys": "8.24.1" + "@typescript-eslint/types": "8.25.0", + "@typescript-eslint/visitor-keys": "8.25.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2531,14 +2878,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.24.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.24.1.tgz", - "integrity": "sha512-/Do9fmNgCsQ+K4rCz0STI7lYB4phTtEXqqCAs3gZW0pnK7lWNkvWd5iW545GSmApm4AzmQXmSqXPO565B4WVrw==", + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.25.0.tgz", + "integrity": "sha512-d77dHgHWnxmXOPJuDWO4FDWADmGQkN5+tt6SFRZz/RtCWl4pHgFl3+WdYCn16+3teG09DY6XtEpf3gGD0a186g==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.24.1", - "@typescript-eslint/utils": "8.24.1", + "@typescript-eslint/typescript-estree": "8.25.0", + "@typescript-eslint/utils": "8.25.0", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, @@ -2555,11 +2901,10 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.24.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.24.1.tgz", - "integrity": "sha512-9kqJ+2DkUXiuhoiYIUvIYjGcwle8pcPpdlfkemGvTObzgmYfJ5d0Qm6jwb4NBXP9W1I5tss0VIAnWFumz3mC5A==", + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.25.0.tgz", + "integrity": "sha512-+vUe0Zb4tkNgznQwicsvLUJgZIRs6ITeWSCclX1q85pR1iOiaj+4uZJIUp//Z27QWu5Cseiw3O3AR8hVpax7Aw==", "dev": true, - "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -2569,14 +2914,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.24.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.1.tgz", - "integrity": "sha512-UPyy4MJ/0RE648DSKQe9g0VDSehPINiejjA6ElqnFaFIhI6ZEiZAkUI0D5MCk0bQcTf/LVqZStvQ6K4lPn/BRg==", + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.25.0.tgz", + "integrity": "sha512-ZPaiAKEZ6Blt/TPAx5Ot0EIB/yGtLI2EsGoY6F7XKklfMxYQyvtL+gT/UCqkMzO0BVFHLDlzvFqQzurYahxv9Q==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.24.1", - "@typescript-eslint/visitor-keys": "8.24.1", + "@typescript-eslint/types": "8.25.0", + "@typescript-eslint/visitor-keys": "8.25.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -2596,16 +2940,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.24.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.24.1.tgz", - "integrity": "sha512-OOcg3PMMQx9EXspId5iktsI3eMaXVwlhC8BvNnX6B5w9a4dVgpkQZuU8Hy67TolKcl+iFWq0XX+jbDGN4xWxjQ==", + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.25.0.tgz", + "integrity": "sha512-syqRbrEv0J1wywiLsK60XzHnQe/kRViI3zwFALrNEgnntn1l24Ra2KvOAWwWbWZ1lBZxZljPDGOq967dsl6fkA==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.24.1", - "@typescript-eslint/types": "8.24.1", - "@typescript-eslint/typescript-estree": "8.24.1" + "@typescript-eslint/scope-manager": "8.25.0", + "@typescript-eslint/types": "8.25.0", + "@typescript-eslint/typescript-estree": "8.25.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2620,13 +2963,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.24.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.1.tgz", - "integrity": "sha512-EwVHlp5l+2vp8CoqJm9KikPZgi3gbdZAtabKT9KPShGeOcJhsv4Zdo3oc8T8I0uKEmYoU4ItyxbptjF08enaxg==", + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.25.0.tgz", + "integrity": "sha512-kCYXKAum9CecGVHGij7muybDfTS2sD3t0L4bJsEZLkyrXUImiCTq1M3LG2SRtOhiHFwMR9wAFplpT6XHYjTkwQ==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.24.1", + "@typescript-eslint/types": "8.25.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -2642,7 +2984,6 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -2655,7 +2996,6 @@ "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.1.tgz", "integrity": "sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==", "dev": true, - "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" }, @@ -2669,7 +3009,6 @@ "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.1.31.tgz", "integrity": "sha512-xlsLr+e+AXZ/00eVZCtNmMeCJoJaRCoLDiAgLcxgQjSS1EertieB2MUHf8xIqPKs9lECc/UpL+y1xDcpvi02hw==", "dev": true, - "license": "MIT", "peerDependencies": { "@typescript-eslint/utils": ">= 8.0", "eslint": ">= 8.57.0", @@ -2686,14 +3025,13 @@ } }, "node_modules/@vitest/expect": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.6.tgz", - "integrity": "sha512-zBduHf/ja7/QRX4HdP1DSq5XrPgdN+jzLOwaTq/0qZjYfgETNFCKf9nOAp2j3hmom3oTbczuUzrzg9Hafh7hNg==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.7.tgz", + "integrity": "sha512-QP25f+YJhzPfHrHfYHtvRn+uvkCFCqFtW9CktfBxmB+25QqWsx7VB2As6f4GmwllHLDhXNHvqedwhvMmSnNmjw==", "dev": true, - "license": "MIT", "dependencies": { - "@vitest/spy": "3.0.6", - "@vitest/utils": "3.0.6", + "@vitest/spy": "3.0.7", + "@vitest/utils": "3.0.7", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" }, @@ -2702,13 +3040,12 @@ } }, "node_modules/@vitest/mocker": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.6.tgz", - "integrity": "sha512-KPztr4/tn7qDGZfqlSPQoF2VgJcKxnDNhmfR3VgZ6Fy1bO8T9Fc1stUiTXtqz0yG24VpD00pZP5f8EOFknjNuQ==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.7.tgz", + "integrity": "sha512-qui+3BLz9Eonx4EAuR/i+QlCX6AUZ35taDQgwGkK/Tw6/WgwodSrjN1X2xf69IA/643ZX5zNKIn2svvtZDrs4w==", "dev": true, - "license": "MIT", "dependencies": { - "@vitest/spy": "3.0.6", + "@vitest/spy": "3.0.7", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, @@ -2728,12 +3065,20 @@ } } }, - "node_modules/@vitest/pretty-format": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.6.tgz", - "integrity": "sha512-Zyctv3dbNL+67qtHfRnUE/k8qxduOamRfAL1BurEIQSyOEFffoMvx2pnDSSbKAAVxY0Ej2J/GH2dQKI0W2JyVg==", + "node_modules/@vitest/mocker/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.7.tgz", + "integrity": "sha512-CiRY0BViD/V8uwuEzz9Yapyao+M9M008/9oMOSQydwbwb+CMokEq3XVaF3XK/VWaOK0Jm9z7ENhybg70Gtxsmg==", "dev": true, - "license": "MIT", "dependencies": { "tinyrainbow": "^2.0.0" }, @@ -2742,13 +3087,12 @@ } }, "node_modules/@vitest/runner": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.6.tgz", - "integrity": "sha512-JopP4m/jGoaG1+CBqubV/5VMbi7L+NQCJTu1J1Pf6YaUbk7bZtaq5CX7p+8sY64Sjn1UQ1XJparHfcvTTdu9cA==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.7.tgz", + "integrity": "sha512-WeEl38Z0S2ZcuRTeyYqaZtm4e26tq6ZFqh5y8YD9YxfWuu0OFiGFUbnxNynwLjNRHPsXyee2M9tV7YxOTPZl2g==", "dev": true, - "license": "MIT", "dependencies": { - "@vitest/utils": "3.0.6", + "@vitest/utils": "3.0.7", "pathe": "^2.0.3" }, "funding": { @@ -2756,13 +3100,12 @@ } }, "node_modules/@vitest/snapshot": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.6.tgz", - "integrity": "sha512-qKSmxNQwT60kNwwJHMVwavvZsMGXWmngD023OHSgn873pV0lylK7dwBTfYP7e4URy5NiBCHHiQGA9DHkYkqRqg==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.7.tgz", + "integrity": "sha512-eqTUryJWQN0Rtf5yqCGTQWsCFOQe4eNz5Twsu21xYEcnFJtMU5XvmG0vgebhdLlrHQTSq5p8vWHJIeJQV8ovsA==", "dev": true, - "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.0.6", + "@vitest/pretty-format": "3.0.7", "magic-string": "^0.30.17", "pathe": "^2.0.3" }, @@ -2771,11 +3114,10 @@ } }, "node_modules/@vitest/spy": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.6.tgz", - "integrity": "sha512-HfOGx/bXtjy24fDlTOpgiAEJbRfFxoX3zIGagCqACkFKKZ/TTOE6gYMKXlqecvxEndKFuNHcHqP081ggZ2yM0Q==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.7.tgz", + "integrity": "sha512-4T4WcsibB0B6hrKdAZTM37ekuyFZt2cGbEGd2+L0P8ov15J1/HUsUaqkXEQPNAWr4BtPPe1gI+FYfMHhEKfR8w==", "dev": true, - "license": "MIT", "dependencies": { "tinyspy": "^3.0.2" }, @@ -2784,13 +3126,12 @@ } }, "node_modules/@vitest/utils": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.6.tgz", - "integrity": "sha512-18ktZpf4GQFTbf9jK543uspU03Q2qya7ZGya5yiZ0Gx0nnnalBvd5ZBislbl2EhLjM8A8rt4OilqKG7QwcGkvQ==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.7.tgz", + "integrity": "sha512-xePVpCRfooFX3rANQjwoditoXgWb1MaFbzmGuPP59MK6i13mrnDw/yEIyJudLeW6/38mCNcwCiJIGmpDPibAIg==", "dev": true, - "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.0.6", + "@vitest/pretty-format": "3.0.7", "loupe": "^3.1.3", "tinyrainbow": "^2.0.0" }, @@ -2803,7 +3144,6 @@ "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.11.tgz", "integrity": "sha512-lN2C1+ByfW9/JRPpqScuZt/4OrUUse57GLI6TbLgTIqBVemdl1wNcZ1qYGEo2+Gw8coYLgCy7SuKqn6IrQcQgg==", "dev": true, - "license": "MIT", "dependencies": { "@volar/source-map": "2.4.11" } @@ -2812,15 +3152,13 @@ "version": "2.4.11", "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.11.tgz", "integrity": "sha512-ZQpmafIGvaZMn/8iuvCFGrW3smeqkq/IIh9F1SdSx9aUl0J4Iurzd6/FhmjNO5g2ejF3rT45dKskgXWiofqlZQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@volar/typescript": { "version": "2.4.11", "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.11.tgz", "integrity": "sha512-2DT+Tdh88Spp5PyPbqhyoYavYCPDsqbHLFwcUI9K1NlY1YgUJvujGdrqUp0zWxnW7KWNTr3xSpMuv2WnaTKDAw==", "dev": true, - "license": "MIT", "dependencies": { "@volar/language-core": "2.4.11", "path-browserify": "^1.0.1", @@ -2831,15 +3169,13 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.2.5.tgz", "integrity": "sha512-lOz4t39ZdmU4DJAa2hwPYmKc8EsuGa2U0L9KaZaOJUt0UwQNjNA3AZTq6uEivhOKhhG1Wvy96SvYBoFmCg3uuw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@vue/babel-plugin-jsx": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.2.5.tgz", "integrity": "sha512-zTrNmOd4939H9KsRIGmmzn3q2zvv1mjxkYZHgqHZgDrXz5B1Q3WyGEjO2f+JrmKghvl1JIRcvo63LgM1kH5zFg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.8", @@ -2866,7 +3202,6 @@ "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.2.5.tgz", "integrity": "sha512-U/ibkQrf5sx0XXRnUZD1mo5F7PkpKyTbfXM3a3rC4YnUz6crHEz9Jg09jzzL6QYlXNto/9CePdOg/c87O4Nlfg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "^7.24.7", "@babel/helper-module-imports": "^7.24.7", @@ -2882,7 +3217,6 @@ "version": "3.5.13", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz", "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", - "license": "MIT", "dependencies": { "@babel/parser": "^7.25.3", "@vue/shared": "3.5.13", @@ -2891,17 +3225,10 @@ "source-map-js": "^1.2.0" } }, - "node_modules/@vue/compiler-core/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "license": "MIT" - }, "node_modules/@vue/compiler-dom": { "version": "3.5.13", "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz", "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", - "license": "MIT", "dependencies": { "@vue/compiler-core": "3.5.13", "@vue/shared": "3.5.13" @@ -2911,7 +3238,6 @@ "version": "3.5.13", "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz", "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==", - "license": "MIT", "dependencies": { "@babel/parser": "^7.25.3", "@vue/compiler-core": "3.5.13", @@ -2924,17 +3250,10 @@ "source-map-js": "^1.2.0" } }, - "node_modules/@vue/compiler-sfc/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "license": "MIT" - }, "node_modules/@vue/compiler-ssr": { "version": "3.5.13", "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz", "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==", - "license": "MIT", "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/shared": "3.5.13" @@ -2945,7 +3264,6 @@ "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", "dev": true, - "license": "MIT", "dependencies": { "de-indent": "^1.0.2", "he": "^1.2.0" @@ -2954,15 +3272,13 @@ "node_modules/@vue/devtools-api": { "version": "6.6.4", "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", - "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", - "license": "MIT" + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==" }, "node_modules/@vue/devtools-core": { "version": "7.7.2", "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-7.7.2.tgz", "integrity": "sha512-lexREWj1lKi91Tblr38ntSsy6CvI8ba7u+jmwh2yruib/ltLUcsIzEjCnrkh1yYGGIKXbAuYV2tOG10fGDB9OQ==", "dev": true, - "license": "MIT", "dependencies": { "@vue/devtools-kit": "^7.7.2", "@vue/devtools-shared": "^7.7.2", @@ -2976,9 +3292,9 @@ } }, "node_modules/@vue/devtools-core/node_modules/nanoid": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.0.tgz", - "integrity": "sha512-zDAl/llz8Ue/EblwSYwdxGBYfj46IM1dhjVi8dyp9LQffoIGxJEAHj2oeZ4uNcgycSRcQ83CnfcZqEJzVDLcDw==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.2.tgz", + "integrity": "sha512-b+CiXQCNMUGe0Ri64S9SXFcP9hogjAJ2Rd6GdVxhPLRm7mhGaM7VgOvCAJ1ZshfHbqVDI3uqTI5C8/GaKuLI7g==", "dev": true, "funding": [ { @@ -2986,7 +3302,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "bin": { "nanoid": "bin/nanoid.js" }, @@ -2999,7 +3314,6 @@ "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.2.tgz", "integrity": "sha512-CY0I1JH3Z8PECbn6k3TqM1Bk9ASWxeMtTCvZr7vb+CHi+X/QwQm5F1/fPagraamKMAHVfuuCbdcnNg1A4CYVWQ==", "dev": true, - "license": "MIT", "dependencies": { "@vue/devtools-shared": "^7.7.2", "birpc": "^0.2.19", @@ -3015,7 +3329,6 @@ "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.2.tgz", "integrity": "sha512-uBFxnp8gwW2vD6FrJB8JZLUzVb6PNRG0B0jBnHsOH8uKyva2qINY8PTF5Te4QlTbMDqU5K6qtJDr6cNsKWhbOA==", "dev": true, - "license": "MIT", "dependencies": { "rfdc": "^1.4.1" } @@ -3025,7 +3338,6 @@ "resolved": "https://registry.npmjs.org/@vue/eslint-config-prettier/-/eslint-config-prettier-10.2.0.tgz", "integrity": "sha512-GL3YBLwv/+b86yHcNNfPJxOTtVFJ4Mbc9UU3zR+KVoG7SwGTjPT+32fXamscNumElhcpXW3mT0DgzS9w32S7Bw==", "dev": true, - "license": "MIT", "dependencies": { "eslint-config-prettier": "^10.0.1", "eslint-plugin-prettier": "^5.2.2" @@ -3040,7 +3352,6 @@ "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-14.4.0.tgz", "integrity": "sha512-daU+eAekEeVz3CReE4PRW25fe+OJDKwE28jHN6LimDEnuFMbJ6H4WGogEpNof276wVP6UvzOeJQfLFjB5mW29A==", "dev": true, - "license": "MIT", "dependencies": { "@typescript-eslint/utils": "^8.23.0", "fast-glob": "^3.3.3", @@ -3062,11 +3373,10 @@ } }, "node_modules/@vue/language-core": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.2.tgz", - "integrity": "sha512-QotO41kurE5PLf3vrNgGTk3QswO2PdUFjBwNiOi7zMmGhwb25PSTh9hD1MCgKC06AVv+8sZQvlL3Do4TTVHSiQ==", + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.6.tgz", + "integrity": "sha512-7IQTvwVOvhYSzcizZ2hAdqJjI+SaJS2GO7EnDlSlQ77drwl5UzNa2IZm9pO9MdMxrlw24CGI/Lo3xpCjM26veg==", "dev": true, - "license": "MIT", "dependencies": { "@volar/language-core": "~2.4.11", "@vue/compiler-dom": "^3.5.0", @@ -3090,7 +3400,6 @@ "version": "3.5.13", "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz", "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==", - "license": "MIT", "dependencies": { "@vue/shared": "3.5.13" } @@ -3099,7 +3408,6 @@ "version": "3.5.13", "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.13.tgz", "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==", - "license": "MIT", "dependencies": { "@vue/reactivity": "3.5.13", "@vue/shared": "3.5.13" @@ -3109,7 +3417,6 @@ "version": "3.5.13", "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz", "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==", - "license": "MIT", "dependencies": { "@vue/reactivity": "3.5.13", "@vue/runtime-core": "3.5.13", @@ -3121,7 +3428,6 @@ "version": "3.5.13", "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.13.tgz", "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==", - "license": "MIT", "dependencies": { "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13" @@ -3133,15 +3439,13 @@ "node_modules/@vue/shared": { "version": "3.5.13", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz", - "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==", - "license": "MIT" + "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==" }, "node_modules/@vue/test-utils": { "version": "2.4.6", "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.6.tgz", "integrity": "sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==", "dev": true, - "license": "MIT", "dependencies": { "js-beautify": "^1.14.9", "vue-component-type-helpers": "^2.0.0" @@ -3152,7 +3456,6 @@ "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.7.0.tgz", "integrity": "sha512-ku2uNz5MaZ9IerPPUyOHzyjhXoX2kVJaVf7hL315DC17vS6IiZRmmCPfggNbU16QTvM80+uYYy3eYJB59WCtvg==", "dev": true, - "license": "MIT", "peerDependencies": { "typescript": "5.x", "vue": "^3.4.0" @@ -3167,26 +3470,12 @@ } }, "node_modules/abbrev": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.0.tgz", - "integrity": "sha512-+/kfrslGQ7TNV2ecmQwMJj/B65g5KVq1/L3SGVZ3tCYGqlzFuFCGBZJtMP99wH3NpEUyAjn0zPdPUg0D+DwrOA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/accepts": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, "engines": { - "node": ">= 0.6" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/acorn": { @@ -3194,7 +3483,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, - "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -3207,7 +3495,6 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, - "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -3217,7 +3504,6 @@ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", "dev": true, - "license": "MIT", "dependencies": { "acorn": "^8.11.0" }, @@ -3226,13 +3512,15 @@ } }, "node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", - "dev": true, - "license": "MIT", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "optional": true, + "dependencies": { + "debug": "4" + }, "engines": { - "node": ">= 14" + "node": ">= 6.0.0" } }, "node_modules/agentkeepalive": { @@ -3265,7 +3553,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -3281,17 +3568,18 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-1.0.4.tgz", "integrity": "sha512-DJqqQD3XcsaQcQ1s+iE2jDUZmmQpXwHiR6fCAim/w87luaW+vmLY8fMlrdkmRwzaFXhkxf3rqPCR59tKVv1MDw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, - "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/ansi-styles": { @@ -3299,7 +3587,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -3334,20 +3621,17 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "license": "Python-2.0" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "license": "MIT", "engines": { "node": ">=8" } @@ -3357,23 +3641,14 @@ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true, - "license": "MIT" - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base64-js": { "version": "1.5.1", @@ -3407,7 +3682,6 @@ "resolved": "https://registry.npmjs.org/birpc/-/birpc-0.2.19.tgz", "integrity": "sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/antfu" } @@ -3422,53 +3696,16 @@ "readable-stream": "^3.4.0" } }, - "node_modules/body-parser": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.1.0.tgz", - "integrity": "sha512-/hPxh61E+ll0Ujp24Ilm64cykicul1ypfwjVttduAiEdtnJFvLePSrIPk+HMImtNv5270wOGCb1Tns2rybMkoQ==", - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.0", - "http-errors": "^2.0.0", - "iconv-lite": "^0.5.2", - "on-finished": "^2.4.1", - "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -3477,7 +3714,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -3504,7 +3740,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", @@ -3546,7 +3781,6 @@ "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", "dev": true, - "license": "MIT", "dependencies": { "run-applescript": "^7.0.0" }, @@ -3557,21 +3791,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -3672,55 +3896,19 @@ "node": ">=8" } }, - "node_modules/cacache/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001700", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001700.tgz", - "integrity": "sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==", + "version": "1.0.30001701", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001701.tgz", + "integrity": "sha512-faRs/AW3jA9nTwmJBSO1PQ6L/EOgsB5HMQQq4iCu5zhPgVVgO/pZRHlmatwijZKetFw8/Pr4q6dEN8sJuq8qTw==", "dev": true, "funding": [ { @@ -3735,15 +3923,13 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ], - "license": "CC-BY-4.0" + ] }, "node_modules/chai": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", "dev": true, - "license": "MIT", "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", @@ -3760,7 +3946,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3777,7 +3962,6 @@ "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 16" } @@ -3804,7 +3988,6 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, - "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -3814,18 +3997,74 @@ "node": ">=12" } }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/code-block-writer": { "version": "13.0.3", "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", - "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", - "license": "MIT" + "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==" }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -3837,8 +4076,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/color-support": { "version": "1.1.3", @@ -3852,27 +4090,12 @@ "node_modules/colorette": { "version": "2.0.19", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", - "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", - "license": "MIT" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==" }, "node_modules/commander": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "license": "MIT", "engines": { "node": ">=14" } @@ -3881,15 +4104,13 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "devOptional": true, - "license": "MIT" + "devOptional": true }, "node_modules/config-chain": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", "dev": true, - "license": "MIT", "dependencies": { "ini": "^1.3.4", "proto-list": "~1.2.1" @@ -3901,58 +4122,17 @@ "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", "optional": true }, - "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } + "dev": true }, "node_modules/copy-anything": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", "dev": true, - "license": "MIT", "dependencies": { "is-what": "^4.1.8" }, @@ -3967,15 +4147,13 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, - "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3990,7 +4168,6 @@ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, - "license": "MIT", "bin": { "cssesc": "bin/cssesc" }, @@ -3998,58 +4175,26 @@ "node": ">=4" } }, - "node_modules/cssstyle": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.2.1.tgz", - "integrity": "sha512-9+vem03dMXG7gDmZ62uqmRiMRNtinIZ9ZyuF6BdxzfOD+FdN5hretzynkn0ReS2DO2GSw76RWHs0UmJPI2zUjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@asamuzakjp/css-color": "^2.8.2", - "rrweb-cssom": "^0.8.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "license": "MIT" - }, - "node_modules/data-urls": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", - "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0" - }, - "engines": { - "node": ">=18" - } + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/dataloader": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.3.tgz", - "integrity": "sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==", - "license": "MIT" + "integrity": "sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==" }, "node_modules/de-indent": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "license": "MIT", "dependencies": { "ms": "^2.1.3" }, @@ -4062,13 +4207,6 @@ } } }, - "node_modules/decimal.js": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", - "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", - "dev": true, - "license": "MIT" - }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -4088,7 +4226,6 @@ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -4105,15 +4242,13 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/default-browser": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", "dev": true, - "license": "MIT", "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" @@ -4130,7 +4265,6 @@ "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -4143,7 +4277,6 @@ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -4151,41 +4284,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", "optional": true }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, "node_modules/detect-libc": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", @@ -4199,7 +4303,6 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -4208,7 +4311,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -4220,7 +4322,6 @@ "version": "16.4.7", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", - "license": "BSD-2-Clause", "engines": { "node": ">=12" }, @@ -4228,20 +4329,6 @@ "url": "https://dotenvx.com" } }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/dwengo-1-backend": { "resolved": "backend", "link": true @@ -4254,15 +4341,13 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/editorconfig": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", "dev": true, - "license": "MIT", "dependencies": { "@one-ini/wasm": "0.1.1", "commander": "^10.0.0", @@ -4281,7 +4366,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -4292,34 +4376,17 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, "node_modules/electron-to-chromium": { - "version": "1.5.102", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.102.tgz", - "integrity": "sha512-eHhqaja8tE/FNpIiBrvBjFV/SSKpyWHLvxuR9dPTdo+3V9ppdLmFB7ZZQ98qNovcngPLYIz0oOBF9P0FfZef5Q==", - "dev": true, - "license": "ISC" + "version": "1.5.109", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.109.tgz", + "integrity": "sha512-AidaH9JETVRr9DIPGfp1kAarm/W6hRJTPuCnkF+2MqhF4KaAgRIcBc8nvjk+YMXZhwfISof/7WG29eS4iGxQLQ==", + "dev": true }, "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true }, "node_modules/encoding": { "version": "0.1.13", @@ -4330,18 +4397,6 @@ "iconv-lite": "^0.6.2" } }, - "node_modules/encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -4354,7 +4409,6 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -4382,63 +4436,15 @@ "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-0.1.5.tgz", "integrity": "sha512-xHku1X40RO+fO8yJ8Wh2f2rZWVjqyhb1zgq1yZ8aZRQkv6OOKhKWRUaht3eSCUbAOBaKIgM+ykwFLE+QUxgGeg==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/antfu" } }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "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==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/es-module-lexer": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } + "dev": true }, "node_modules/esbuild": { "version": "0.25.0", @@ -4446,7 +4452,6 @@ "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -4485,23 +4490,15 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -4510,22 +4507,21 @@ } }, "node_modules/eslint": { - "version": "9.20.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.20.1.tgz", - "integrity": "sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g==", + "version": "9.21.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.21.0.tgz", + "integrity": "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.19.0", - "@eslint/core": "^0.11.0", - "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "9.20.0", - "@eslint/plugin-kit": "^0.2.5", + "@eslint/config-array": "^0.19.2", + "@eslint/core": "^0.12.0", + "@eslint/eslintrc": "^3.3.0", + "@eslint/js": "9.21.0", + "@eslint/plugin-kit": "^0.2.7", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.1", + "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", @@ -4570,11 +4566,10 @@ } }, "node_modules/eslint-config-prettier": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.0.1.tgz", - "integrity": "sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.0.2.tgz", + "integrity": "sha512-1105/17ZIMjmCOJOPNfVdbXafLCLj3hPmkmB7dLgt7XsQ/zkxSuDerE/xgO3RxoHysR1N1whmquY0lSn2O0VLg==", "dev": true, - "license": "MIT", "bin": { "eslint-config-prettier": "build/bin/cli.js" }, @@ -4582,47 +4577,11 @@ "eslint": ">=7.0.0" } }, - "node_modules/eslint-plugin-playwright": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-2.2.0.tgz", - "integrity": "sha512-qSQpAw7RcSzE3zPp8FMGkthaCWovHZ/BsXtpmnGax9vQLIovlh1bsZHEa2+j2lv9DWhnyeLM/qZmp7ffQZfQvg==", - "dev": true, - "license": "MIT", - "workspaces": [ - "examples" - ], - "dependencies": { - "globals": "^13.23.0" - }, - "engines": { - "node": ">=16.6.0" - }, - "peerDependencies": { - "eslint": ">=8.40.0" - } - }, - "node_modules/eslint-plugin-playwright/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint-plugin-prettier": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz", "integrity": "sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw==", "dev": true, - "license": "MIT", "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.9.1" @@ -4653,7 +4612,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.32.0.tgz", "integrity": "sha512-b/Y05HYmnB/32wqVcjxjHZzNpwxj1onBOvqW89W+V+XNG1dRuaFbNd3vT9CLbr2LXjEoq+3vn8DanWf7XU22Ug==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "globals": "^13.24.0", @@ -4676,7 +4634,6 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, - "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -4692,7 +4649,6 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -4709,7 +4665,6 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -4722,7 +4677,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4733,7 +4687,6 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -4746,7 +4699,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -4758,7 +4710,6 @@ "version": "3.2.25", "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", - "license": "MIT", "engines": { "node": ">=6" } @@ -4768,7 +4719,6 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", @@ -4786,7 +4736,6 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -4798,7 +4747,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -4812,7 +4760,6 @@ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -4825,7 +4772,6 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -4838,46 +4784,29 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/execa": { "version": "9.5.2", "resolved": "https://registry.npmjs.org/execa/-/execa-9.5.2.tgz", "integrity": "sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==", "dev": true, - "license": "MIT", "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.3", @@ -4908,100 +4837,30 @@ } }, "node_modules/expect-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz", - "integrity": "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.0.tgz", + "integrity": "sha512-80F22aiJ3GLyVnS/B3HzgR6RelZVumzj9jkL0Rhz4h0xYbNW9PjlQz5h3J/SShErbXBc295vseR4/MIbVmUbeA==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=12.0.0" } }, - "node_modules/express": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.0.1.tgz", - "integrity": "sha512-ORF7g6qGnD+YtUG9yx4DFoqCShNMmUKiXuT5oWMHiOvt/4WFbHC6yCwQMTSBMno7AqntNCAzzcnnjowRkTL9eQ==", - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.0.1", - "content-disposition": "^1.0.0", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "^1.2.1", - "debug": "4.3.6", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "^2.0.0", - "fresh": "2.0.0", - "http-errors": "2.0.0", - "merge-descriptors": "^2.0.0", - "methods": "~1.1.2", - "mime-types": "^3.0.0", - "on-finished": "2.4.1", - "once": "1.4.0", - "parseurl": "~1.3.3", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "router": "^2.0.0", - "safe-buffer": "5.2.1", - "send": "^1.1.0", - "serve-static": "^2.1.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "^2.0.0", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/express/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "license": "MIT" - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/fast-diff": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true, - "license": "Apache-2.0" + "dev": true }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -5017,7 +4876,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -5029,21 +4887,18 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/fastq": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz", - "integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==", - "license": "ISC", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "dependencies": { "reusify": "^1.0.4" } @@ -5053,7 +4908,6 @@ "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.8.0.tgz", "integrity": "sha512-chzvGjd+Sp7KUvPHZv6EXV5Ir3Q7kYNpCr4aHrRW79qFtTefmQZNny+W1pW9kf5zeE6dikku2W50W/wAH2xWgw==", "dev": true, - "license": "MIT", "bin": { "figlet": "bin/index.js" }, @@ -5066,7 +4920,6 @@ "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", "dev": true, - "license": "MIT", "dependencies": { "is-unicode-supported": "^2.0.0" }, @@ -5082,7 +4935,6 @@ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, - "license": "MIT", "dependencies": { "flat-cache": "^4.0.0" }, @@ -5099,7 +4951,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -5107,54 +4958,11 @@ "node": ">=8" } }, - "node_modules/finalhandler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.0.0.tgz", - "integrity": "sha512-MX6Zo2adDViYh+GcxxB1dpO43eypOGUOL12rLCOTMQv/DfIbpSJUy4oQIIZhVZkH9e+bZWKMon0XHFEju16tkQ==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, - "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -5171,7 +4979,6 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, - "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" @@ -5184,17 +4991,15 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "dev": true, - "license": "ISC", "dependencies": { - "cross-spawn": "^7.0.0", + "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" }, "engines": { @@ -5204,63 +5009,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/form-data": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", - "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/form-data/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/form-data/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -5270,7 +5018,6 @@ "version": "11.3.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", - "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -5302,11 +5049,6 @@ "node": ">=8" } }, - "node_modules/fs-minipass/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -5314,12 +5056,11 @@ "optional": true }, "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "hasInstallScript": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -5332,7 +5073,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5409,7 +5149,6 @@ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -5419,63 +5158,23 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, - "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/get-intrinsic": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", - "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "function-bind": "^1.1.2", - "get-proto": "^1.0.0", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "license": "MIT", "engines": { "node": ">=8.0.0" } }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/get-stream": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", "dev": true, - "license": "MIT", "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" @@ -5492,7 +5191,6 @@ "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", "dev": true, - "license": "MIT", "dependencies": { "resolve-pkg-maps": "^1.0.0" }, @@ -5503,8 +5201,7 @@ "node_modules/getopts": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.3.0.tgz", - "integrity": "sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==", - "license": "MIT" + "integrity": "sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==" }, "node_modules/github-from-package": { "version": "0.0.0", @@ -5516,7 +5213,6 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, - "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -5537,7 +5233,6 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, - "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -5550,7 +5245,6 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -5562,7 +5256,6 @@ "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -5578,69 +5271,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -5651,7 +5301,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -5664,7 +5313,6 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, - "license": "MIT", "bin": { "he": "bin/he" } @@ -5673,28 +5321,13 @@ "version": "5.5.3", "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/html-encoding-sniffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-encoding": "^3.1.1" - }, - "engines": { - "node": ">=18" - } + "dev": true }, "node_modules/html-tags": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" }, @@ -5708,48 +5341,31 @@ "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "optional": true }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "license": "MIT", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "optional": true, "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", + "@tootallnate/once": "1", + "agent-base": "6", "debug": "4" }, "engines": { - "node": ">= 14" + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" } }, "node_modules/human-signals": { @@ -5757,7 +5373,6 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz", "integrity": "sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=18.18.0" } @@ -5772,12 +5387,12 @@ } }, "node_modules/iconv-lite": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.2.tgz", - "integrity": "sha512-kERHXvpSaB4aU3eANwidg79K8FlrN77m8G9V+0vOR3HYaRifrlwMEpT7ZBJqLSEIHnEgJTHcWK82wwLwwKwtag==", - "license": "MIT", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" @@ -5806,7 +5421,6 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "license": "MIT", "engines": { "node": ">= 4" } @@ -5816,7 +5430,6 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, - "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -5833,7 +5446,6 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "devOptional": true, - "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -5867,20 +5479,17 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC" + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "node_modules/interpret": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", - "license": "MIT", "engines": { "node": ">= 0.10" } @@ -5898,20 +5507,10 @@ "node": ">= 12" } }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, "node_modules/is-core-module": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "license": "MIT", "dependencies": { "hasown": "^2.0.2" }, @@ -5927,7 +5526,6 @@ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "dev": true, - "license": "MIT", "bin": { "is-docker": "cli.js" }, @@ -5942,7 +5540,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5952,7 +5549,6 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "devOptional": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -5961,7 +5557,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -5974,7 +5569,6 @@ "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", "dev": true, - "license": "MIT", "dependencies": { "is-docker": "^3.0.0" }, @@ -5998,7 +5592,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -6008,7 +5601,6 @@ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -6016,25 +5608,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT" - }, "node_modules/is-stream": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -6047,7 +5625,6 @@ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -6060,7 +5637,6 @@ "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", "dev": true, - "license": "MIT", "engines": { "node": ">=12.13" }, @@ -6073,7 +5649,6 @@ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", "dev": true, - "license": "MIT", "dependencies": { "is-inside-container": "^1.0.0" }, @@ -6088,15 +5663,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "devOptional": true, - "license": "ISC" + "devOptional": true }, "node_modules/jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, - "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -6112,23 +5685,21 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", "dev": true, - "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" } }, "node_modules/js-beautify": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.3.tgz", - "integrity": "sha512-rKKGuyTxGNlyN4EQKWzNndzXpi0bOl8Gl8YQAW1as/oMz0XhD6sHJO1hTvoBDOSzKuJb9WkwoAb34FfdkKMv2A==", + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.4.tgz", + "integrity": "sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==", "dev": true, - "license": "MIT", "dependencies": { "config-chain": "^1.1.13", "editorconfig": "^1.0.4", "glob": "^10.4.2", "js-cookie": "^3.0.5", - "nopt": "^8.0.0" + "nopt": "^7.2.1" }, "bin": { "css-beautify": "js/bin/css-beautify.js", @@ -6144,7 +5715,6 @@ "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", "dev": true, - "license": "MIT", "engines": { "node": ">=14" } @@ -6153,14 +5723,12 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -6174,63 +5742,11 @@ "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", "optional": true }, - "node_modules/jsdom": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.0.0.tgz", - "integrity": "sha512-BZYDGVAIriBWTpIxYzrXjv3E/4u8+/pSG5bQdIYCbNCGOvsPkDQfTVLAIXAf9ETdCpduCVTkDe2NNZ8NIwUVzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssstyle": "^4.2.1", - "data-urls": "^5.0.0", - "decimal.js": "^10.4.3", - "form-data": "^4.0.1", - "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.6", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.16", - "parse5": "^7.2.1", - "rrweb-cssom": "^0.8.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^5.0.0", - "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^3.1.1", - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.1.0", - "ws": "^8.18.0", - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "canvas": "^3.0.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsdom/node_modules/xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18" - } - }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, - "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -6242,15 +5758,13 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/json-parse-even-better-errors": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-4.0.0.tgz", "integrity": "sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==", "dev": true, - "license": "MIT", "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -6259,22 +5773,19 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -6286,7 +5797,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -6299,7 +5809,6 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, - "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -6308,7 +5817,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/knex/-/knex-3.1.0.tgz", "integrity": "sha512-GLoII6hR0c4ti243gMs5/1Rb3B+AjwMOfjYm97pu0FOQa7JH56hgBxYf5WK2525ceSbBY1cjeZ9yk99GPMB6Kw==", - "license": "MIT", "dependencies": { "colorette": "2.0.19", "commander": "^10.0.0", @@ -6359,7 +5867,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -6375,14 +5882,12 @@ "node_modules/knex/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "license": "MIT" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/knex/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "license": "MIT", "engines": { "node": ">=8" } @@ -6391,15 +5896,13 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, - "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -6413,7 +5916,6 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, - "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -6427,35 +5929,30 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/loupe": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/magic-string": { "version": "0.30.17", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", - "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } @@ -6464,8 +5961,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/make-fetch-happen": { "version": "9.1.0", @@ -6494,45 +5990,6 @@ "node": ">= 10" } }, - "node_modules/make-fetch-happen/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "optional": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "optional": true, - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/make-fetch-happen/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "optional": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/make-fetch-happen/node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -6557,39 +6014,6 @@ "node": ">=8" } }, - "node_modules/make-fetch-happen/node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", - "optional": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/make-fetch-happen/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -6599,41 +6023,18 @@ "node": ">= 0.10.0" } }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "license": "MIT", "engines": { "node": ">= 8" } }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -6646,32 +6047,10 @@ "version": "6.4.6", "resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-6.4.6.tgz", "integrity": "sha512-Lr3uFK06O/4F/AtQAsuYD6QH7DgmUooSVFVGf1y02IuiKVFKOMJ4iKimkRMyoA+ykKhgYIp8WiaEqbWJVuz4Vw==", - "license": "MIT", "engines": { "node": ">= 18.12.0" } }, - "node_modules/mime-db": { - "version": "1.53.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz", - "integrity": "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.0.tgz", - "integrity": "sha512-XqoSHeCGjVClAmoGFG3lVFqQFRIrTVw2OH3axRqAcfaw+gHWIfnASS92AV+Rl/mk0MupgZTRHQOjxY6YVnzK5w==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.53.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/mimic-response": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", @@ -6687,7 +6066,6 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -6702,7 +6080,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6712,7 +6089,6 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, - "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } @@ -6741,12 +6117,6 @@ "node": ">=8" } }, - "node_modules/minipass-collect/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, "node_modules/minipass-fetch": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", @@ -6776,12 +6146,6 @@ "node": ">=8" } }, - "node_modules/minipass-fetch/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, "node_modules/minipass-flush": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", @@ -6806,12 +6170,6 @@ "node": ">=8" } }, - "node_modules/minipass-flush/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, "node_modules/minipass-pipeline": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", @@ -6836,12 +6194,6 @@ "node": ">=8" } }, - "node_modules/minipass-pipeline/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, "node_modules/minipass-sized": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", @@ -6866,12 +6218,6 @@ "node": ">=8" } }, - "node_modules/minipass-sized/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, "node_modules/minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", @@ -6895,17 +6241,11 @@ "node": ">=8" } }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/mitt": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/mkdirp": { "version": "1.0.4", @@ -6928,7 +6268,6 @@ "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" } @@ -6936,15 +6275,13 @@ "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/muggle-string": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/nanoid": { "version": "3.3.8", @@ -6956,7 +6293,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -6973,14 +6309,13 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "optional": true, "engines": { "node": ">= 0.6" } @@ -7093,23 +6428,21 @@ "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/nopt": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", - "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", "dev": true, - "license": "ISC", "dependencies": { - "abbrev": "^3.0.0" + "abbrev": "^2.0.0" }, "bin": { "nopt": "bin/nopt.js" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm-normalize-package-bin": { @@ -7117,7 +6450,6 @@ "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz", "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==", "dev": true, - "license": "ISC", "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -7127,7 +6459,6 @@ "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-7.0.2.tgz", "integrity": "sha512-7tXR+r9hzRNOPNTvXegM+QzCuMjzUIIq66VDunL6j60O4RrExx32XUhlrS7UK4VcdGw5/Wxzb3kfNcFix9JKDA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", "cross-spawn": "^7.0.6", @@ -7154,7 +6485,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -7167,7 +6497,6 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, - "license": "ISC", "engines": { "node": ">=16" } @@ -7177,7 +6506,6 @@ "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", "dev": true, - "license": "ISC", "dependencies": { "isexe": "^3.1.1" }, @@ -7193,7 +6521,6 @@ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", "dev": true, - "license": "MIT", "dependencies": { "path-key": "^4.0.0", "unicorn-magic": "^0.3.0" @@ -7210,7 +6537,6 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -7239,7 +6565,6 @@ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" }, @@ -7247,42 +6572,10 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/nwsapi": { - "version": "2.2.16", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz", - "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", "dependencies": { "wrappy": "1" } @@ -7292,7 +6585,6 @@ "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", "dev": true, - "license": "MIT", "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", @@ -7311,7 +6603,6 @@ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, - "license": "MIT", "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -7329,7 +6620,6 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, - "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -7345,7 +6635,6 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, - "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -7375,15 +6664,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, - "license": "BlueOak-1.0.0" + "dev": true }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, - "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -7405,7 +6692,6 @@ "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -7418,7 +6704,6 @@ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", "dev": true, - "license": "MIT", "dependencies": { "entities": "^4.5.0" }, @@ -7426,27 +6711,16 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", - "license": "MIT" + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -7465,7 +6739,6 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -7473,15 +6746,13 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "license": "MIT" + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, - "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -7493,20 +6764,10 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/path-to-regexp": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", - "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", - "license": "MIT", - "engines": { - "node": ">=16" - } - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "license": "MIT", "engines": { "node": ">=8" } @@ -7515,15 +6776,13 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/pathval": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 14.16" } @@ -7532,14 +6791,12 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/pg": { "version": "8.13.2", "resolved": "https://registry.npmjs.org/pg/-/pg-8.13.2.tgz", "integrity": "sha512-L5QkPvTjVWWHbLaFjCkOSplpb2uCiRYbg0IJ2okCy5ClYfWlSgDDnvdR6dyw3EWAH2AfS4j8E61QFI7gLfTtlw==", - "license": "MIT", "dependencies": { "pg-connection-string": "^2.7.0", "pg-pool": "^3.7.1", @@ -7566,20 +6823,17 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", - "license": "MIT", "optional": true }, "node_modules/pg-connection-string": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", - "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==", - "license": "MIT" + "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" }, "node_modules/pg-int8": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", - "license": "ISC", "engines": { "node": ">=4.0.0" } @@ -7588,7 +6842,6 @@ "version": "3.7.1", "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.1.tgz", "integrity": "sha512-xIOsFoh7Vdhojas6q3596mXFsR8nwBQBXX5JiV7p9buEVAGqYL4yFzclON5P9vFrpu1u7Zwl2oriyDa89n0wbw==", - "license": "MIT", "peerDependencies": { "pg": ">=8.0" } @@ -7596,14 +6849,12 @@ "node_modules/pg-protocol": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.1.tgz", - "integrity": "sha512-gjTHWGYWsEgy9MsY0Gp6ZJxV24IjDqdpTW7Eh0x+WfJLFsm/TJx1MzL6T0D88mBvkpxotCQ6TwW6N+Kko7lhgQ==", - "license": "MIT" + "integrity": "sha512-gjTHWGYWsEgy9MsY0Gp6ZJxV24IjDqdpTW7Eh0x+WfJLFsm/TJx1MzL6T0D88mBvkpxotCQ6TwW6N+Kko7lhgQ==" }, "node_modules/pg-types": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "license": "MIT", "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", @@ -7619,7 +6870,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", - "license": "MIT", "engines": { "node": ">=4" } @@ -7628,7 +6878,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7637,7 +6886,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "license": "MIT", "dependencies": { "xtend": "^4.0.0" }, @@ -7648,14 +6896,12 @@ "node_modules/pg/node_modules/pg-connection-string": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.7.0.tgz", - "integrity": "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==", - "license": "MIT" + "integrity": "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==" }, "node_modules/pgpass": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", - "license": "MIT", "dependencies": { "split2": "^4.1.0" } @@ -7663,14 +6909,12 @@ "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "license": "MIT", "engines": { "node": ">=8.6" }, @@ -7683,7 +6927,6 @@ "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", "dev": true, - "license": "MIT", "bin": { "pidtree": "bin/pidtree.js" }, @@ -7696,7 +6939,6 @@ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.50.1.tgz", "integrity": "sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "playwright-core": "1.50.1" }, @@ -7715,7 +6957,6 @@ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.1.tgz", "integrity": "sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==", "dev": true, - "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" }, @@ -7723,21 +6964,6 @@ "node": ">=18" } }, - "node_modules/playwright/node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/postcss": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", @@ -7756,7 +6982,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", @@ -7771,7 +6996,6 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dev": true, - "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -7784,7 +7008,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz", "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==", - "license": "MIT", "engines": { "node": ">=12" } @@ -7793,7 +7016,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7802,7 +7024,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz", "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==", - "license": "MIT", "engines": { "node": ">=12" } @@ -7811,7 +7032,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-4.0.2.tgz", "integrity": "sha512-EMsphSQ1YkQqKZL2cuG0zHkmjCCzQqQ71l2GXITqRwjhRleCdv00bDk/ktaSi0LnlaPzAc3535KTrjXsTdtx7A==", - "license": "MIT", "engines": { "node": ">=12" } @@ -7846,17 +7066,15 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/prettier": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.1.tgz", - "integrity": "sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.2.tgz", + "integrity": "sha512-lc6npv5PH7hVqozBR7lkBNOGXV9vMwROAPlumdBkX0wTbbzPu/U1hk5yL8p2pt4Xoc+2mkT8t/sow2YrV/M5qg==", "dev": true, - "license": "MIT", "peer": true, "bin": { "prettier": "bin/prettier.cjs" @@ -7873,7 +7091,6 @@ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, - "license": "MIT", "dependencies": { "fast-diff": "^1.1.2" }, @@ -7886,7 +7103,6 @@ "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.2.0.tgz", "integrity": "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==", "dev": true, - "license": "MIT", "dependencies": { "parse-ms": "^4.0.0" }, @@ -7920,21 +7136,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "dev": true, - "license": "ISC" - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } + "dev": true }, "node_modules/pump": { "version": "3.0.2", @@ -7950,26 +7152,10 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -7987,44 +7173,7 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", - "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.6.3", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } + ] }, "node_modules/rc": { "version": "1.2.8", @@ -8053,7 +7202,6 @@ "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-4.0.0.tgz", "integrity": "sha512-qpt8EwugBWDw2cgE2W+/3oxC+KTez2uSVR8JU9Q36TXPAGCaozfQUs59v4j4GFpWTaw0i6hAZSvOmu1J0uOEUg==", "dev": true, - "license": "ISC", "dependencies": { "json-parse-even-better-errors": "^4.0.0", "npm-normalize-package-bin": "^4.0.0" @@ -8079,7 +7227,6 @@ "version": "0.8.0", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", - "license": "MIT", "dependencies": { "resolve": "^1.20.0" }, @@ -8090,15 +7237,13 @@ "node_modules/reflect-metadata": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", - "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", - "license": "Apache-2.0" + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==" }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -8107,7 +7252,6 @@ "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", - "license": "MIT", "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", @@ -8128,7 +7272,6 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } @@ -8138,7 +7281,6 @@ "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } @@ -8153,10 +7295,9 @@ } }, "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "license": "MIT", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -8166,8 +7307,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/rimraf": { "version": "3.0.2", @@ -8229,11 +7369,10 @@ } }, "node_modules/rollup": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz", - "integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.9.tgz", + "integrity": "sha512-nF5XYqWWp9hx/LrpC8sZvvvmq0TeTjQgaZHYmAgwysT9nh8sWnZhBnM8ZyVbbJFIQBLwHDNoMqsBZBbUo4U8sQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "1.0.6" }, @@ -8245,55 +7384,33 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.34.8", - "@rollup/rollup-android-arm64": "4.34.8", - "@rollup/rollup-darwin-arm64": "4.34.8", - "@rollup/rollup-darwin-x64": "4.34.8", - "@rollup/rollup-freebsd-arm64": "4.34.8", - "@rollup/rollup-freebsd-x64": "4.34.8", - "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", - "@rollup/rollup-linux-arm-musleabihf": "4.34.8", - "@rollup/rollup-linux-arm64-gnu": "4.34.8", - "@rollup/rollup-linux-arm64-musl": "4.34.8", - "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", - "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", - "@rollup/rollup-linux-riscv64-gnu": "4.34.8", - "@rollup/rollup-linux-s390x-gnu": "4.34.8", - "@rollup/rollup-linux-x64-gnu": "4.34.8", - "@rollup/rollup-linux-x64-musl": "4.34.8", - "@rollup/rollup-win32-arm64-msvc": "4.34.8", - "@rollup/rollup-win32-ia32-msvc": "4.34.8", - "@rollup/rollup-win32-x64-msvc": "4.34.8", + "@rollup/rollup-android-arm-eabi": "4.34.9", + "@rollup/rollup-android-arm64": "4.34.9", + "@rollup/rollup-darwin-arm64": "4.34.9", + "@rollup/rollup-darwin-x64": "4.34.9", + "@rollup/rollup-freebsd-arm64": "4.34.9", + "@rollup/rollup-freebsd-x64": "4.34.9", + "@rollup/rollup-linux-arm-gnueabihf": "4.34.9", + "@rollup/rollup-linux-arm-musleabihf": "4.34.9", + "@rollup/rollup-linux-arm64-gnu": "4.34.9", + "@rollup/rollup-linux-arm64-musl": "4.34.9", + "@rollup/rollup-linux-loongarch64-gnu": "4.34.9", + "@rollup/rollup-linux-powerpc64le-gnu": "4.34.9", + "@rollup/rollup-linux-riscv64-gnu": "4.34.9", + "@rollup/rollup-linux-s390x-gnu": "4.34.9", + "@rollup/rollup-linux-x64-gnu": "4.34.9", + "@rollup/rollup-linux-x64-musl": "4.34.9", + "@rollup/rollup-win32-arm64-msvc": "4.34.9", + "@rollup/rollup-win32-ia32-msvc": "4.34.9", + "@rollup/rollup-win32-x64-msvc": "4.34.9", "fsevents": "~2.3.2" } }, - "node_modules/router": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.1.0.tgz", - "integrity": "sha512-/m/NSLxeYEgWNtyC+WtNHCF7jbGxOibVWKnn+1Psff4dJGOfoXP+MuC/f2CwSmyiHdOIzYnYFp4W6GxWfekaLA==", - "license": "MIT", - "dependencies": { - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/rrweb-cssom": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", - "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", - "dev": true, - "license": "MIT" - }, "node_modules/run-applescript": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -8319,7 +7436,6 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } @@ -8341,33 +7457,17 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "license": "ISC", - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/semver": { "version": "7.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -8375,92 +7475,17 @@ "node": ">=10" } }, - "node_modules/send": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.1.0.tgz", - "integrity": "sha512-v67WcEouB5GxbTWL/4NeToqcZiAWEq90N888fczVArY8A79J0L4FD7vj5hm3eUMua5EpoQ59wa/oovY6TLvRUA==", - "license": "MIT", - "dependencies": { - "debug": "^4.3.5", - "destroy": "^1.2.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^0.5.2", - "http-errors": "^2.0.0", - "mime-types": "^2.1.35", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/send/node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/send/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/send/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-static": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.1.0.tgz", - "integrity": "sha512-A3We5UfEjG8Z7VkDv6uItWw6HY2bBSBJT1KtVESn6EOoOr2jAxNhxWCLY3jDE2WcuHXByWju74ck3ZgLwL8xmA==", - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.0.0" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "optional": true }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, - "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -8473,7 +7498,6 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -8483,79 +7507,6 @@ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, "engines": { "node": ">= 0.4" }, @@ -8567,15 +7518,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "license": "ISC", "engines": { "node": ">=14" }, @@ -8631,7 +7580,6 @@ "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", "integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==", "dev": true, - "license": "MIT", "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", @@ -8645,7 +7593,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "license": "MIT", "engines": { "node": ">=8" } @@ -8688,23 +7635,10 @@ "node": ">= 10" } }, - "node_modules/socks-proxy-agent/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "optional": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -8714,7 +7648,6 @@ "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -8723,7 +7656,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "license": "ISC", "engines": { "node": ">= 10.x" } @@ -8761,7 +7693,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -8798,34 +7729,17 @@ "node": ">=8" } }, - "node_modules/ssri/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } + "dev": true }, "node_modules/std-env": { "version": "3.8.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz", "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/string_decoder": { "version": "1.3.0", @@ -8836,18 +7750,20 @@ } }, "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, - "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/string-width-cjs": { @@ -8856,7 +7772,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -8866,12 +7781,26 @@ "node": ">=8" } }, - "node_modules/strip-ansi": { + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -8879,13 +7808,27 @@ "node": ">=8" } }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -8893,12 +7836,20 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } @@ -8908,7 +7859,6 @@ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -8921,7 +7871,6 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" }, @@ -8934,7 +7883,6 @@ "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz", "integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==", "dev": true, - "license": "MIT", "dependencies": { "copy-anything": "^3.0.2" }, @@ -8947,7 +7895,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -8959,7 +7906,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -8973,19 +7919,11 @@ "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", "dev": true }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true, - "license": "MIT" - }, "node_modules/synckit": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", "dev": true, - "license": "MIT", "dependencies": { "@pkgr/core": "^0.1.0", "tslib": "^2.6.2" @@ -9052,16 +7990,10 @@ "node": ">=8" } }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/tarn": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz", "integrity": "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==", - "license": "MIT", "engines": { "node": ">=8.0.0" } @@ -9070,7 +8002,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==", - "license": "MIT", "engines": { "node": ">=8" } @@ -9079,22 +8010,19 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/tinyexec": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/tinypool": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz", "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==", "dev": true, - "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" } @@ -9104,7 +8032,6 @@ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", "dev": true, - "license": "MIT", "engines": { "node": ">=14.0.0" } @@ -9114,36 +8041,14 @@ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=14.0.0" } }, - "node_modules/tldts": { - "version": "6.1.78", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.78.tgz", - "integrity": "sha512-fSgYrW0ITH0SR/CqKMXIruYIPpNu5aDgUp22UhYoSrnUQwc7SBqifEBFNce7AAcygUPBo6a/gbtcguWdmko4RQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "tldts-core": "^6.1.78" - }, - "bin": { - "tldts": "bin/cli.js" - } - }, - "node_modules/tldts-core": { - "version": "6.1.78", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.78.tgz", - "integrity": "sha512-jS0svNsB99jR6AJBmfmEWuKIgz91Haya91Z43PATaeHJ24BkMoNRb/jlaD37VYjb0mYf6gRL/HOnvS1zEnYBiw==", - "dev": true, - "license": "MIT" - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -9151,57 +8056,20 @@ "node": ">=8.0" } }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, "node_modules/totalist": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/tough-cookie": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.1.tgz", - "integrity": "sha512-Ek7HndSVkp10hmHP9V4qZO1u+pn1RU5sI0Fw+jCU3lyvuMZcgqsNgc6CmJJZyByK4Vm/qotGRJlfgAX8q+4JiA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tldts": "^6.1.32" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/tr46": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", - "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/ts-api-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", "dev": true, - "license": "MIT", "engines": { "node": ">=18.12" }, @@ -9213,7 +8081,6 @@ "version": "25.0.1", "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-25.0.1.tgz", "integrity": "sha512-QJEiTdnz1YjrB3JFhd626gX4rKHDLSjSVMvGGG4v7ONc3RBwa0Eei98G9AT9uNFDMtV54JyuXsFeC+OH0n6bXQ==", - "license": "MIT", "dependencies": { "@ts-morph/common": "~0.26.0", "code-block-writer": "^13.0.3" @@ -9224,7 +8091,6 @@ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, - "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -9268,7 +8134,6 @@ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", "dev": true, - "license": "MIT", "dependencies": { "json5": "^2.2.2", "minimist": "^1.2.6", @@ -9282,15 +8147,13 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD" + "dev": true }, "node_modules/tsx": { "version": "4.19.3", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.3.tgz", "integrity": "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==", "dev": true, - "license": "MIT", "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" @@ -9311,7 +8174,6 @@ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -9337,7 +8199,6 @@ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, - "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -9350,7 +8211,6 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -9358,26 +8218,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/type-is": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.0.tgz", - "integrity": "sha512-gd0sGezQYCbWSbkZr75mln4YBidWUN60+devscpLF5mtRDUpiaTvKpBNrdaCvel1NdR2k6vclXybU5fBd2i+nw==", - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/typescript": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "devOptional": true, - "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9387,15 +8232,14 @@ } }, "node_modules/typescript-eslint": { - "version": "8.24.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.24.1.tgz", - "integrity": "sha512-cw3rEdzDqBs70TIcb0Gdzbt6h11BSs2pS0yaq7hDWDBtCCSei1pPSUXE9qUdQ/Wm9NgFg8mKtMt1b8fTHIl1jA==", + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.25.0.tgz", + "integrity": "sha512-TxRdQQLH4g7JkoFlYG3caW5v1S6kEkz8rqt80iQJZUYPq1zD1Ra7HfQBJJ88ABRaMvHAXnwRvRB4V+6sQ9xN5Q==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.24.1", - "@typescript-eslint/parser": "8.24.1", - "@typescript-eslint/utils": "8.24.1" + "@typescript-eslint/eslint-plugin": "8.25.0", + "@typescript-eslint/parser": "8.25.0", + "@typescript-eslint/utils": "8.25.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9413,15 +8257,13 @@ "version": "6.20.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/unicorn-magic": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -9451,24 +8293,14 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", "engines": { "node": ">= 10.0.0" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/update-browserslist-db": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz", - "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "dev": true, "funding": [ { @@ -9484,7 +8316,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" @@ -9501,7 +8332,6 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -9509,17 +8339,7 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/uuid": { "version": "11.1.0", @@ -9537,17 +8357,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, - "license": "MIT" - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } + "dev": true }, "node_modules/vite": { "version": "6.2.0", @@ -9625,7 +8435,6 @@ "resolved": "https://registry.npmjs.org/vite-hot-client/-/vite-hot-client-0.2.4.tgz", "integrity": "sha512-a1nzURqO7DDmnXqabFOliz908FRmIppkBKsJthS8rbe8hBEXwEwe4C3Pp33Z1JoFCYfVL4kTOMLKk0ZZxREIeA==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/antfu" }, @@ -9634,11 +8443,10 @@ } }, "node_modules/vite-node": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.6.tgz", - "integrity": "sha512-s51RzrTkXKJrhNbUzQRsarjmAae7VmMPAsRT7lppVpIg6mK3zGthP9Hgz0YQQKuNcF+Ii7DfYk3Fxz40jRmePw==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.7.tgz", + "integrity": "sha512-2fX0QwX4GkkkpULXdT1Pf4q0tC1i1lFOyseKoonavXUNlQ77KpW2XqBGGNIm/J4Ows4KxgGJzDguYVPKwG/n5A==", "dev": true, - "license": "MIT", "dependencies": { "cac": "^6.7.14", "debug": "^4.4.0", @@ -9661,7 +8469,6 @@ "resolved": "https://registry.npmjs.org/vite-plugin-inspect/-/vite-plugin-inspect-0.8.9.tgz", "integrity": "sha512-22/8qn+LYonzibb1VeFZmISdVao5kC22jmEKm24vfFE8siEn47EpVcCLYMv6iKOYMJfjSvSJfueOwcFCkUnV3A==", "dev": true, - "license": "MIT", "dependencies": { "@antfu/utils": "^0.7.10", "@rollup/pluginutils": "^5.1.3", @@ -9693,7 +8500,6 @@ "resolved": "https://registry.npmjs.org/vite-plugin-vue-devtools/-/vite-plugin-vue-devtools-7.7.2.tgz", "integrity": "sha512-5V0UijQWiSBj32blkyPEqIbzc6HO9c1bwnBhx+ay2dzU0FakH+qMdNUT8nF9BvDE+i6I1U8CqCuJiO20vKEdQw==", "dev": true, - "license": "MIT", "dependencies": { "@vue/devtools-core": "^7.7.2", "@vue/devtools-kit": "^7.7.2", @@ -9715,7 +8521,6 @@ "resolved": "https://registry.npmjs.org/vite-plugin-vue-inspector/-/vite-plugin-vue-inspector-5.3.1.tgz", "integrity": "sha512-cBk172kZKTdvGpJuzCCLg8lJ909wopwsu3Ve9FsL1XsnLBiRT9U3MePcqrgGHgCX2ZgkqZmAGR8taxw+TV6s7A==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.23.0", "@babel/plugin-proposal-decorators": "^7.23.0", @@ -9731,20 +8536,33 @@ "vite": "^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0" } }, - "node_modules/vitest": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.6.tgz", - "integrity": "sha512-/iL1Sc5VeDZKPDe58oGK4HUFLhw6b5XdY1MYawjuSaDA4sEfYlY9HnS6aCEG26fX+MgUi7MwlduTBHHAI/OvMA==", + "node_modules/vite/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/vitest": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.7.tgz", + "integrity": "sha512-IP7gPK3LS3Fvn44x30X1dM9vtawm0aesAa2yBIZ9vQf+qB69NXC5776+Qmcr7ohUXIQuLhk7xQR0aSUIDPqavg==", "dev": true, - "license": "MIT", "dependencies": { - "@vitest/expect": "3.0.6", - "@vitest/mocker": "3.0.6", - "@vitest/pretty-format": "^3.0.6", - "@vitest/runner": "3.0.6", - "@vitest/snapshot": "3.0.6", - "@vitest/spy": "3.0.6", - "@vitest/utils": "3.0.6", + "@vitest/expect": "3.0.7", + "@vitest/mocker": "3.0.7", + "@vitest/pretty-format": "^3.0.7", + "@vitest/runner": "3.0.7", + "@vitest/snapshot": "3.0.7", + "@vitest/spy": "3.0.7", + "@vitest/utils": "3.0.7", "chai": "^5.2.0", "debug": "^4.4.0", "expect-type": "^1.1.0", @@ -9756,7 +8574,7 @@ "tinypool": "^1.0.2", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0", - "vite-node": "3.0.6", + "vite-node": "3.0.7", "why-is-node-running": "^2.3.0" }, "bin": { @@ -9772,8 +8590,8 @@ "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.0.6", - "@vitest/ui": "3.0.6", + "@vitest/browser": "3.0.7", + "@vitest/ui": "3.0.7", "happy-dom": "*", "jsdom": "*" }, @@ -9805,14 +8623,12 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/vue": { "version": "3.5.13", "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz", "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==", - "license": "MIT", "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/compiler-sfc": "3.5.13", @@ -9830,18 +8646,16 @@ } }, "node_modules/vue-component-type-helpers": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.2.2.tgz", - "integrity": "sha512-6lLY+n2xz2kCYshl59mL6gy8OUUTmkscmDFMO8i7Lj+QKwgnIFUZmM1i/iTYObtrczZVdw7UakPqDTGwVSGaRg==", - "dev": true, - "license": "MIT" + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.2.6.tgz", + "integrity": "sha512-kFdh3gw9DN+h6d/JEQfW8GbNG4XHwiJSJO1T3Akx1QtLT0tS/4njk4JpAzQ6i9PvOwALg3ESMnS31xr2wXluXA==", + "dev": true }, "node_modules/vue-eslint-parser": { "version": "9.4.3", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz", "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^4.3.4", "eslint-scope": "^7.1.1", @@ -9866,7 +8680,6 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -9883,7 +8696,6 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -9900,7 +8712,6 @@ "version": "10.0.5", "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-10.0.5.tgz", "integrity": "sha512-9/gmDlCblz3i8ypu/afiIc/SUIfTTE1mr0mZhb9pk70xo2csHAM9mp2gdQ3KD2O0AM3Hz/5ypb+FycTj/lHlPQ==", - "license": "MIT", "dependencies": { "@intlify/core-base": "10.0.5", "@intlify/shared": "10.0.5", @@ -9920,7 +8731,6 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.0.tgz", "integrity": "sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==", - "license": "MIT", "dependencies": { "@vue/devtools-api": "^6.6.4" }, @@ -9932,14 +8742,13 @@ } }, "node_modules/vue-tsc": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.2.2.tgz", - "integrity": "sha512-1icPKkxAA5KTAaSwg0wVWdE48EdsH8fgvcbAiqojP4jXKl6LEM3soiW1aG/zrWrFt8Mw1ncG2vG1PvpZpVfehA==", + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.2.6.tgz", + "integrity": "sha512-TI6eAnWPatONEpVAZt1etbSrh8tDpHOLSlRqKGudOK5WKVnBGzHXUi0KR4UCsf2o5P+5285w4HF+5avhfH7IMA==", "dev": true, - "license": "MIT", "dependencies": { "@volar/typescript": "~2.4.11", - "@vue/language-core": "2.2.2" + "@vue/language-core": "2.2.6" }, "bin": { "vue-tsc": "bin/vue-tsc.js" @@ -9949,10 +8758,9 @@ } }, "node_modules/vuetify": { - "version": "3.7.13", - "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.7.13.tgz", - "integrity": "sha512-4+RuQU+zLtXhlN2eZUpKXums9ftzUzhMeiNEJvvJY4XdOzVwUCth2dTnEZkSF6EKdLHk3WhtRk0cIWXZxpBvcw==", - "license": "MIT", + "version": "3.7.14", + "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.7.14.tgz", + "integrity": "sha512-L5oD0x3Wrp49Khp+16dRykAFUZq6WXqX7OHLTwXnyEliJ48ERC9WfEtN0YOuEIhor/b2IOZXl+11fs/m452/Lw==", "engines": { "node": "^12.20 || >=14.13" }, @@ -9978,95 +8786,11 @@ } } }, - "node_modules/w3c-xmlserializer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/w3c-xmlserializer/node_modules/xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/whatwg-encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/whatwg-url": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.1.tgz", - "integrity": "sha512-mDGf9diDad/giZ/Sm9Xi2YcyzaFpbdLpJPr+E9fSkyQ7KpQD4SdFcugkRQYzhmfI4KeV4Qpnn2sKPdo+kmsgRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "tr46": "^5.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "devOptional": true, - "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -10082,7 +8806,6 @@ "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, - "license": "MIT", "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" @@ -10149,24 +8872,22 @@ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, - "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -10178,7 +8899,6 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -10191,56 +8911,77 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/xml-name-validator": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=12" } }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true, - "license": "MIT" - }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", "engines": { "node": ">=0.4" } @@ -10250,24 +8991,20 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, - "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, - "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -10286,17 +9023,56 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, - "license": "ISC", "engines": { "node": ">=12" } }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -10306,7 +9082,6 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -10319,7 +9094,6 @@ "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.1.tgz", "integrity": "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, From 74765577d5cbb149dcd26403b425965199056d95 Mon Sep 17 00:00:00 2001 From: Lint Action Date: Sat, 1 Mar 2025 10:33:27 +0000 Subject: [PATCH 022/180] style: fix linting issues met ESLint --- backend/src/data/dwengo-entity-repository.ts | 6 +++--- backend/src/data/questions/answer-repository.ts | 2 +- backend/src/data/questions/question-repository.ts | 2 +- .../src/entities/assignments/assignment.entity.ts | 6 +++--- backend/src/entities/assignments/group.entity.ts | 4 ++-- .../src/entities/assignments/submission.entity.ts | 6 +++--- .../entities/classes/class-join-request.entity.ts | 6 +++--- backend/src/entities/classes/class.entity.ts | 4 ++-- .../entities/classes/teacher-invitation.entity.ts | 6 +++--- backend/src/entities/content/attachment.entity.ts | 2 +- .../src/entities/content/learning-object.entity.ts | 10 +++++----- backend/src/entities/content/learning-path.entity.ts | 12 ++++++------ backend/src/entities/questions/answer.entity.ts | 4 ++-- backend/src/entities/questions/question.entity.ts | 4 ++-- backend/src/entities/users/student.entity.ts | 6 +++--- backend/src/entities/users/teacher.entity.ts | 2 +- backend/src/mikro-orm.config.ts | 6 +++--- backend/src/routes/assignment.ts | 4 ++-- backend/src/routes/class.ts | 4 ++-- backend/src/routes/group.ts | 10 +++++----- backend/src/routes/login.ts | 6 +++--- backend/src/routes/question.ts | 4 ++-- backend/src/routes/student.ts | 12 ++++++------ backend/src/routes/submission.ts | 4 ++-- backend/src/routes/teacher.ts | 10 +++++----- backend/tests/data/users.test.ts | 4 ++-- 26 files changed, 73 insertions(+), 73 deletions(-) diff --git a/backend/src/data/dwengo-entity-repository.ts b/backend/src/data/dwengo-entity-repository.ts index 368f3a2c..e29d9ede 100644 --- a/backend/src/data/dwengo-entity-repository.ts +++ b/backend/src/data/dwengo-entity-repository.ts @@ -4,13 +4,13 @@ export abstract class DwengoEntityRepository< T extends object, > extends EntityRepository { public async save(entity: T) { - let em = this.getEntityManager(); + const em = this.getEntityManager(); em.persist(entity); await em.flush(); } public async deleteWhere(query: FilterQuery) { - let toDelete = await this.findOne(query); - let em = this.getEntityManager(); + const toDelete = await this.findOne(query); + const em = this.getEntityManager(); if (toDelete) { em.remove(toDelete); await em.flush(); diff --git a/backend/src/data/questions/answer-repository.ts b/backend/src/data/questions/answer-repository.ts index 6a2629f4..6c45211c 100644 --- a/backend/src/data/questions/answer-repository.ts +++ b/backend/src/data/questions/answer-repository.ts @@ -9,7 +9,7 @@ export class AnswerRepository extends DwengoEntityRepository { author: Teacher; content: string; }): Promise { - let answerEntity = new Answer(); + const answerEntity = new Answer(); answerEntity.toQuestion = answer.toQuestion; answerEntity.author = answer.author; answerEntity.content = answer.content; diff --git a/backend/src/data/questions/question-repository.ts b/backend/src/data/questions/question-repository.ts index 517305f1..8852a9ba 100644 --- a/backend/src/data/questions/question-repository.ts +++ b/backend/src/data/questions/question-repository.ts @@ -9,7 +9,7 @@ export class QuestionRepository extends DwengoEntityRepository { author: Student; content: string; }): Promise { - let questionEntity = new Question(); + const questionEntity = new Question(); questionEntity.learningObjectHruid = question.loId.hruid; questionEntity.learningObjectLanguage = question.loId.language; questionEntity.learningObjectVersion = question.loId.version; diff --git a/backend/src/entities/assignments/assignment.entity.ts b/backend/src/entities/assignments/assignment.entity.ts index e883632b..7909b107 100644 --- a/backend/src/entities/assignments/assignment.entity.ts +++ b/backend/src/entities/assignments/assignment.entity.ts @@ -12,7 +12,7 @@ import { Language } from '../content/language.js'; @Entity() export class Assignment { - @ManyToOne({ entity: () => Class, primary: true }) + @ManyToOne({ entity: () => {return Class}, primary: true }) within!: Class; @PrimaryKey({ type: 'number' }) @@ -27,9 +27,9 @@ export class Assignment { @Property({ type: 'string' }) learningPathHruid!: string; - @Enum({ items: () => Language }) + @Enum({ items: () => {return Language} }) learningPathLanguage!: Language; - @OneToMany({ entity: () => Group, mappedBy: 'assignment' }) + @OneToMany({ entity: () => {return Group}, mappedBy: 'assignment' }) groups!: Group[]; } diff --git a/backend/src/entities/assignments/group.entity.ts b/backend/src/entities/assignments/group.entity.ts index 80da7d8b..a68eb5a0 100644 --- a/backend/src/entities/assignments/group.entity.ts +++ b/backend/src/entities/assignments/group.entity.ts @@ -4,12 +4,12 @@ import { Student } from '../users/student.entity.js'; @Entity() export class Group { - @ManyToOne({ entity: () => Assignment, primary: true }) + @ManyToOne({ entity: () => {return Assignment}, primary: true }) assignment!: Assignment; @PrimaryKey({ type: 'integer' }) groupNumber!: number; - @ManyToMany({ entity: () => Student }) + @ManyToMany({ entity: () => {return Student} }) members!: Student[]; } diff --git a/backend/src/entities/assignments/submission.entity.ts b/backend/src/entities/assignments/submission.entity.ts index 02cbeeae..bd0936a1 100644 --- a/backend/src/entities/assignments/submission.entity.ts +++ b/backend/src/entities/assignments/submission.entity.ts @@ -8,7 +8,7 @@ export class Submission { @PrimaryKey({ type: 'string' }) learningObjectHruid!: string; - @Enum({ items: () => Language, primary: true }) + @Enum({ items: () => {return Language}, primary: true }) learningObjectLanguage!: Language; @PrimaryKey({ type: 'string' }) @@ -17,13 +17,13 @@ export class Submission { @PrimaryKey({ type: 'integer' }) submissionNumber!: number; - @ManyToOne({ entity: () => Student }) + @ManyToOne({ entity: () => {return Student} }) submitter!: Student; @Property({ type: 'datetime' }) submissionTime!: Date; - @ManyToOne({ entity: () => Group, nullable: true }) + @ManyToOne({ entity: () => {return Group}, nullable: true }) onBehalfOf?: Group; @Property({ type: 'json' }) diff --git a/backend/src/entities/classes/class-join-request.entity.ts b/backend/src/entities/classes/class-join-request.entity.ts index 00cb5185..8e88999c 100644 --- a/backend/src/entities/classes/class-join-request.entity.ts +++ b/backend/src/entities/classes/class-join-request.entity.ts @@ -4,13 +4,13 @@ import { Class } from './class.entity'; @Entity() export class ClassJoinRequest { - @ManyToOne({ entity: () => Student, primary: true }) + @ManyToOne({ entity: () => {return Student}, primary: true }) requester!: Student; - @ManyToOne({ entity: () => Class, primary: true }) + @ManyToOne({ entity: () => {return Class}, primary: true }) class!: Class; - @Enum(() => ClassJoinRequestStatus) + @Enum(() => {return ClassJoinRequestStatus}) status!: ClassJoinRequestStatus; } diff --git a/backend/src/entities/classes/class.entity.ts b/backend/src/entities/classes/class.entity.ts index 1f5835d2..2ad98c84 100644 --- a/backend/src/entities/classes/class.entity.ts +++ b/backend/src/entities/classes/class.entity.ts @@ -17,9 +17,9 @@ export class Class { @Property({ type: 'string' }) displayName!: string; - @ManyToMany(() => Teacher) + @ManyToMany(() => {return Teacher}) teachers!: Collection; - @ManyToMany(() => Student) + @ManyToMany(() => {return Student}) students!: Collection; } diff --git a/backend/src/entities/classes/teacher-invitation.entity.ts b/backend/src/entities/classes/teacher-invitation.entity.ts index 375bf719..feba8fc3 100644 --- a/backend/src/entities/classes/teacher-invitation.entity.ts +++ b/backend/src/entities/classes/teacher-invitation.entity.ts @@ -7,12 +7,12 @@ import { Class } from './class.entity.js'; */ @Entity() export class TeacherInvitation { - @ManyToOne({ entity: () => Teacher, primary: true }) + @ManyToOne({ entity: () => {return Teacher}, primary: true }) sender!: Teacher; - @ManyToOne({ entity: () => Teacher, primary: true }) + @ManyToOne({ entity: () => {return Teacher}, primary: true }) receiver!: Teacher; - @ManyToOne({ entity: () => Class, primary: true }) + @ManyToOne({ entity: () => {return Class}, primary: true }) class!: Class; } diff --git a/backend/src/entities/content/attachment.entity.ts b/backend/src/entities/content/attachment.entity.ts index 5a77d4b7..2ead7262 100644 --- a/backend/src/entities/content/attachment.entity.ts +++ b/backend/src/entities/content/attachment.entity.ts @@ -3,7 +3,7 @@ import { LearningObject } from './learning-object.entity.js'; @Entity() export class Attachment { - @ManyToOne({ entity: () => LearningObject, primary: true }) + @ManyToOne({ entity: () => {return LearningObject}, primary: true }) learningObject!: LearningObject; @PrimaryKey({ type: 'integer' }) diff --git a/backend/src/entities/content/learning-object.entity.ts b/backend/src/entities/content/learning-object.entity.ts index aeee268d..c5bfe08f 100644 --- a/backend/src/entities/content/learning-object.entity.ts +++ b/backend/src/entities/content/learning-object.entity.ts @@ -17,13 +17,13 @@ export class LearningObject { @PrimaryKey({ type: 'string' }) hruid!: string; - @Enum({ items: () => Language, primary: true }) + @Enum({ items: () => {return Language}, primary: true }) language!: Language; @PrimaryKey({ type: 'string' }) version: string = '1'; - @ManyToMany({ entity: () => Teacher }) + @ManyToMany({ entity: () => {return Teacher} }) admins!: Teacher[]; @Property({ type: 'string' }) @@ -47,7 +47,7 @@ export class LearningObject { @Property({ type: 'array' }) skosConcepts!: string[]; - @Embedded({ entity: () => EducationalGoal, array: true }) + @Embedded({ entity: () => {return EducationalGoal}, array: true }) educationalGoals: EducationalGoal[] = []; @Property({ type: 'string' }) @@ -62,7 +62,7 @@ export class LearningObject { @Property({ type: 'integer' }) estimatedTime!: number; - @Embedded({ entity: () => ReturnValue }) + @Embedded({ entity: () => {return ReturnValue} }) returnValue!: ReturnValue; @Property({ type: 'bool' }) @@ -71,7 +71,7 @@ export class LearningObject { @Property({ type: 'string', nullable: true }) contentLocation?: string; - @OneToMany({ entity: () => Attachment, mappedBy: 'learningObject' }) + @OneToMany({ entity: () => {return Attachment}, mappedBy: 'learningObject' }) attachments: Attachment[] = []; @Property({ type: 'blob' }) diff --git a/backend/src/entities/content/learning-path.entity.ts b/backend/src/entities/content/learning-path.entity.ts index f426cdfe..f758dace 100644 --- a/backend/src/entities/content/learning-path.entity.ts +++ b/backend/src/entities/content/learning-path.entity.ts @@ -16,10 +16,10 @@ export class LearningPath { @PrimaryKey({ type: 'string' }) hruid!: string; - @Enum({ items: () => Language, primary: true }) + @Enum({ items: () => {return Language}, primary: true }) language!: Language; - @ManyToMany({ entity: () => Teacher }) + @ManyToMany({ entity: () => {return Teacher} }) admins!: Teacher[]; @Property({ type: 'string' }) @@ -31,7 +31,7 @@ export class LearningPath { @Property({ type: 'blob' }) image!: string; - @Embedded({ entity: () => LearningPathNode, array: true }) + @Embedded({ entity: () => {return LearningPathNode}, array: true }) nodes: LearningPathNode[] = []; } @@ -40,7 +40,7 @@ export class LearningPathNode { @Property({ type: 'string' }) learningObjectHruid!: string; - @Enum({ items: () => Language }) + @Enum({ items: () => {return Language} }) language!: Language; @Property({ type: 'string' }) @@ -52,7 +52,7 @@ export class LearningPathNode { @Property({ type: 'bool' }) startNode!: boolean; - @Embedded({ entity: () => LearningPathTransition, array: true }) + @Embedded({ entity: () => {return LearningPathTransition}, array: true }) transitions!: LearningPathTransition[]; } @@ -61,6 +61,6 @@ export class LearningPathTransition { @Property({ type: 'string' }) condition!: string; - @OneToOne({ entity: () => LearningPathNode }) + @OneToOne({ entity: () => {return LearningPathNode} }) next!: LearningPathNode; } diff --git a/backend/src/entities/questions/answer.entity.ts b/backend/src/entities/questions/answer.entity.ts index b15dce71..2690d50d 100644 --- a/backend/src/entities/questions/answer.entity.ts +++ b/backend/src/entities/questions/answer.entity.ts @@ -4,10 +4,10 @@ import { Teacher } from '../users/teacher.entity'; @Entity() export class Answer { - @ManyToOne({ entity: () => Teacher, primary: true }) + @ManyToOne({ entity: () => {return Teacher}, primary: true }) author!: Teacher; - @ManyToOne({ entity: () => Question, primary: true }) + @ManyToOne({ entity: () => {return Question}, primary: true }) toQuestion!: Question; @PrimaryKey({ type: 'integer' }) diff --git a/backend/src/entities/questions/question.entity.ts b/backend/src/entities/questions/question.entity.ts index 6c0d07e5..5830c816 100644 --- a/backend/src/entities/questions/question.entity.ts +++ b/backend/src/entities/questions/question.entity.ts @@ -7,7 +7,7 @@ export class Question { @PrimaryKey({ type: 'string' }) learningObjectHruid!: string; - @Enum({ items: () => Language, primary: true }) + @Enum({ items: () => {return Language}, primary: true }) learningObjectLanguage!: Language; @PrimaryKey({ type: 'string' }) @@ -16,7 +16,7 @@ export class Question { @PrimaryKey({ type: 'integer' }) sequenceNumber!: number; - @ManyToOne({ entity: () => Student }) + @ManyToOne({ entity: () => {return Student} }) author!: Student; @Property({ type: 'datetime' }) diff --git a/backend/src/entities/users/student.entity.ts b/backend/src/entities/users/student.entity.ts index dc791adc..ccfa7dfc 100644 --- a/backend/src/entities/users/student.entity.ts +++ b/backend/src/entities/users/student.entity.ts @@ -4,12 +4,12 @@ import { Class } from '../classes/class.entity.js'; import { Group } from '../assignments/group.entity.js'; import { StudentRepository } from '../../data/users/student-repository.js'; -@Entity({ repository: () => StudentRepository }) +@Entity({ repository: () => {return StudentRepository} }) export class Student extends User { - @ManyToMany(() => Class) + @ManyToMany(() => {return Class}) classes!: Collection; - @ManyToMany(() => Group) + @ManyToMany(() => {return Group}) groups!: Collection; constructor( diff --git a/backend/src/entities/users/teacher.entity.ts b/backend/src/entities/users/teacher.entity.ts index 2327527c..eaaa8327 100644 --- a/backend/src/entities/users/teacher.entity.ts +++ b/backend/src/entities/users/teacher.entity.ts @@ -4,6 +4,6 @@ import { Class } from '../classes/class.entity.js'; @Entity() export class Teacher extends User { - @ManyToMany(() => Class) + @ManyToMany(() => {return Class}) classes!: Collection; } diff --git a/backend/src/mikro-orm.config.ts b/backend/src/mikro-orm.config.ts index da118827..88996cf9 100644 --- a/backend/src/mikro-orm.config.ts +++ b/backend/src/mikro-orm.config.ts @@ -15,9 +15,9 @@ function config(testingMode: boolean = false): Options { // Workaround: vitest: `TypeError: Unknown file extension ".ts"` (ERR_UNKNOWN_FILE_EXTENSION) // (see https://mikro-orm.io/docs/guide/project-setup#testing-the-endpoint) - dynamicImportProvider: (id) => import(id), + dynamicImportProvider: (id) => {return import(id)}, }; - } else { + } return { driver: PostgreSqlDriver, host: getEnvVar(EnvVars.DbHost), @@ -29,7 +29,7 @@ function config(testingMode: boolean = false): Options { entitiesTs: entitiesTs, debug: true, }; - } + } export default config; diff --git a/backend/src/routes/assignment.ts b/backend/src/routes/assignment.ts index fcb6e9da..eb49144f 100644 --- a/backend/src/routes/assignment.ts +++ b/backend/src/routes/assignment.ts @@ -1,7 +1,7 @@ import express from 'express' const router = express.Router(); -// root endpoint used to search objects +// Root endpoint used to search objects router.get('/', (req, res) => { res.json({ assignments: [ @@ -11,7 +11,7 @@ router.get('/', (req, res) => { }); }); -// information about an assignment with id 'id' +// Information about an assignment with id 'id' router.get('/:id', (req, res) => { res.json({ id: req.params.id, diff --git a/backend/src/routes/class.ts b/backend/src/routes/class.ts index e554a7f2..fa7a2310 100644 --- a/backend/src/routes/class.ts +++ b/backend/src/routes/class.ts @@ -1,7 +1,7 @@ import express from 'express' const router = express.Router(); -// root endpoint used to search objects +// Root endpoint used to search objects router.get('/', (req, res) => { res.json({ classes: [ @@ -11,7 +11,7 @@ router.get('/', (req, res) => { }); }); -// information about an class with id 'id' +// Information about an class with id 'id' router.get('/:id', (req, res) => { res.json({ id: req.params.id, diff --git a/backend/src/routes/group.ts b/backend/src/routes/group.ts index e55dddd1..e951a8a7 100644 --- a/backend/src/routes/group.ts +++ b/backend/src/routes/group.ts @@ -1,7 +1,7 @@ import express from 'express' const router = express.Router(); -// root endpoint used to search objects +// Root endpoint used to search objects router.get('/', (req, res) => { res.json({ groups: [ @@ -11,20 +11,20 @@ router.get('/', (req, res) => { }); }); -// information about a group (members, ... [TODO DOC]) +// Information about a group (members, ... [TODO DOC]) router.get('/:id', (req, res) => { res.json({ id: req.params.id, assignment: '0', students: [ '0' ], submissions: [ '0' ], - // reference to other endpoint - // should be less hardcoded + // Reference to other endpoint + // Should be less hardcoded questions: `/group/${req.params.id}/question`, }); }) -// the list of questions a group has made +// The list of questions a group has made router.get('/:id/question', (req, res) => { res.json({ questions: [ '0' ], diff --git a/backend/src/routes/login.ts b/backend/src/routes/login.ts index 550e6d93..bc2ed3d8 100644 --- a/backend/src/routes/login.ts +++ b/backend/src/routes/login.ts @@ -1,11 +1,11 @@ import express from 'express' const router = express.Router(); -// returns login paths for IDP +// Returns login paths for IDP router.get('/', (req, res) => { res.json({ - // dummy variables, needs to be changed - // with IDP endpoints + // Dummy variables, needs to be changed + // With IDP endpoints leerkracht: '/login-leerkracht', leerling: '/login-leerling', }); diff --git a/backend/src/routes/question.ts b/backend/src/routes/question.ts index 25d168b7..040f742d 100644 --- a/backend/src/routes/question.ts +++ b/backend/src/routes/question.ts @@ -1,7 +1,7 @@ import express from 'express' const router = express.Router(); -// root endpoint used to search objects +// Root endpoint used to search objects router.get('/', (req, res) => { res.json({ questions: [ @@ -11,7 +11,7 @@ router.get('/', (req, res) => { }); }); -// information about an question with id 'id' +// Information about an question with id 'id' router.get('/:id', (req, res) => { res.json({ id: req.params.id, diff --git a/backend/src/routes/student.ts b/backend/src/routes/student.ts index a11c1fbc..bc3f588b 100644 --- a/backend/src/routes/student.ts +++ b/backend/src/routes/student.ts @@ -1,7 +1,7 @@ import express from 'express' const router = express.Router(); -// root endpoint used to search objects +// Root endpoint used to search objects router.get('/', (req, res) => { res.json({ students: [ @@ -11,7 +11,7 @@ router.get('/', (req, res) => { }); }); -// information about a student's profile +// Information about a student's profile router.get('/:id', (req, res) => { res.json({ id: req.params.id, @@ -27,14 +27,14 @@ router.get('/:id', (req, res) => { }); }); -// the list of classes a student is in +// The list of classes a student is in router.get('/:id/classes', (req, res) => { res.json({ classes: [ '0' ], }); }) -// the list of submissions a student has made +// The list of submissions a student has made router.get('/:id/submissions', (req, res) => { res.json({ submissions: [ '0' ], @@ -42,14 +42,14 @@ router.get('/:id/submissions', (req, res) => { }) -// the list of assignments a student has +// The list of assignments a student has router.get('/:id/assignments', (req, res) => { res.json({ assignments: [ '0' ], }); }) -// the list of groups a student is in +// The list of groups a student is in router.get('/:id/groups', (req, res) => { res.json({ groups: [ '0' ], diff --git a/backend/src/routes/submission.ts b/backend/src/routes/submission.ts index 8d09cf8e..98acc842 100644 --- a/backend/src/routes/submission.ts +++ b/backend/src/routes/submission.ts @@ -1,7 +1,7 @@ import express from 'express' const router = express.Router(); -// root endpoint used to search objects +// Root endpoint used to search objects router.get('/', (req, res) => { res.json({ submissions: [ @@ -11,7 +11,7 @@ router.get('/', (req, res) => { }); }); -// information about an submission with id 'id' +// Information about an submission with id 'id' router.get('/:id', (req, res) => { res.json({ id: req.params.id, diff --git a/backend/src/routes/teacher.ts b/backend/src/routes/teacher.ts index 37b3b04b..f9de3aa5 100644 --- a/backend/src/routes/teacher.ts +++ b/backend/src/routes/teacher.ts @@ -1,7 +1,7 @@ import express from 'express' const router = express.Router(); -// root endpoint used to search objects +// Root endpoint used to search objects router.get('/', (req, res) => { res.json({ teachers: [ @@ -11,7 +11,7 @@ router.get('/', (req, res) => { }); }); -// information about a teacher +// Information about a teacher router.get('/:id', (req, res) => { res.json({ id: req.params.id, @@ -27,7 +27,7 @@ router.get('/:id', (req, res) => { }); }) -// the questions students asked a teacher +// The questions students asked a teacher router.get('/:id/questions', (req, res) => { res.json({ questions: [ @@ -36,7 +36,7 @@ router.get('/:id/questions', (req, res) => { }); }); -// invitations to other classes a teacher received +// Invitations to other classes a teacher received router.get('/:id/invitations', (req, res) => { res.json({ invitations: [ @@ -45,7 +45,7 @@ router.get('/:id/invitations', (req, res) => { }); }); -// a list with ids of classes a teacher is in +// A list with ids of classes a teacher is in router.get('/:id/classes', (req, res) => { res.json({ classes: [ diff --git a/backend/tests/data/users.test.ts b/backend/tests/data/users.test.ts index c7cc875d..a982151e 100644 --- a/backend/tests/data/users.test.ts +++ b/backend/tests/data/users.test.ts @@ -18,7 +18,7 @@ describe("StudentRepository", () => { it("should return the queried student after he was added", async () => { await studentRepository.insert(new Student(username, firstName, lastName)); - let retrievedStudent = await studentRepository.findByUsername(username); + const retrievedStudent = await studentRepository.findByUsername(username); expect(retrievedStudent).toBeTruthy(); expect(retrievedStudent?.firstName).toBe(firstName); expect(retrievedStudent?.lastName).toBe(lastName); @@ -27,7 +27,7 @@ describe("StudentRepository", () => { it("should no longer return the queried student after he was removed again", async () => { await studentRepository.deleteByUsername(username); - let retrievedStudent = await studentRepository.findByUsername(username); + const retrievedStudent = await studentRepository.findByUsername(username); expect(retrievedStudent).toBeNull(); }); }); From 17893a6990c1ea1e7dd2306e45d65f54ac1a884e Mon Sep 17 00:00:00 2001 From: Lint Action Date: Sat, 1 Mar 2025 10:33:30 +0000 Subject: [PATCH 023/180] style: fix linting issues met Prettier --- backend/_i18n/de.yml | 478 ++++++++-------- backend/_i18n/en.yml | 466 ++++++++-------- backend/_i18n/fr.yml | 494 ++++++++--------- backend/_i18n/nl.yml | 522 +++++++++--------- backend/src/app.ts | 1 - .../entities/assignments/assignment.entity.ts | 20 +- .../src/entities/assignments/group.entity.ts | 13 +- .../entities/assignments/submission.entity.ts | 20 +- .../classes/class-join-request.entity.ts | 18 +- backend/src/entities/classes/class.entity.ts | 8 +- .../classes/teacher-invitation.entity.ts | 21 +- .../src/entities/content/attachment.entity.ts | 7 +- .../content/learning-object.entity.ts | 33 +- .../entities/content/learning-path.entity.ts | 39 +- .../src/entities/questions/answer.entity.ts | 14 +- .../src/entities/questions/question.entity.ts | 13 +- backend/src/entities/users/student.entity.ts | 14 +- backend/src/entities/users/teacher.entity.ts | 4 +- backend/src/mikro-orm.config.ts | 29 +- backend/src/routes/assignment.ts | 25 +- backend/src/routes/class.ts | 37 +- backend/src/routes/group.ts | 21 +- backend/src/routes/login.ts | 6 +- backend/src/routes/question.ts | 24 +- backend/src/routes/student.ts | 28 +- backend/src/routes/submission.ts | 11 +- backend/src/routes/teacher.ts | 24 +- backend/tests/data/users.test.ts | 32 +- backend/tests/setup-tests.ts | 6 +- backend/vitest.config.ts | 4 +- docker-compose.yml | 20 +- frontend/src/App.vue | 9 +- frontend/src/components/BrowseThemes.vue | 6 +- frontend/src/components/LearningPath.vue | 8 +- frontend/src/components/MenuBar.vue | 10 +- frontend/src/components/errors/NotFound.vue | 8 +- frontend/src/router/index.ts | 44 +- frontend/src/views/HomePage.vue | 8 +- frontend/src/views/LoginPage.vue | 7 +- frontend/src/views/StudentHomepage.vue | 8 +- frontend/src/views/TeacherHomepage.vue | 8 +- .../views/assignments/CreateAssignment.vue | 8 +- .../views/assignments/SingleAssignment.vue | 8 +- .../views/assignments/StudentAssignments.vue | 8 +- .../views/assignments/TeacherAssignments.vue | 8 +- frontend/src/views/classes/CreateClass.vue | 8 +- frontend/src/views/classes/SingleClass.vue | 8 +- frontend/src/views/classes/StudentClasses.vue | 8 +- frontend/src/views/classes/TeacherClasses.vue | 8 +- .../views/discussions/CreateDiscussion.vue | 8 +- .../views/discussions/SingleDiscussion.vue | 8 +- .../views/discussions/StudentDiscussions.vue | 8 +- .../views/discussions/TeacherDiscussions.vue | 8 +- 53 files changed, 1350 insertions(+), 1314 deletions(-) diff --git a/backend/_i18n/de.yml b/backend/_i18n/de.yml index 3356a9aa..08d48473 100644 --- a/backend/_i18n/de.yml +++ b/backend/_i18n/de.yml @@ -7,320 +7,320 @@ curricula_page: algorithms: title: Algorithmen sub_title: Algorithmen - description: "Schüler der zweiten und dritten Klasse (Sekundarstufe) lernen, wie sie Algorithmen verwenden können, um Probleme zu lösen. Sie lernen, wie sie Algorithmen entwerfen und die Effizienz von Algorithmen analysieren können. Sie lernen auch, wie sie Algorithmen zur Problemlösung einsetzen können." - contact: "" + description: 'Schüler der zweiten und dritten Klasse (Sekundarstufe) lernen, wie sie Algorithmen verwenden können, um Probleme zu lösen. Sie lernen, wie sie Algorithmen entwerfen und die Effizienz von Algorithmen analysieren können. Sie lernen auch, wie sie Algorithmen zur Problemlösung einsetzen können.' + contact: '' teaser: https://www.youtube.com/embed/2B6gZ9HdQ1Y basics_ai: title: Basisprincipes van AI sub_title: Basisprincipes van AI - description: "Onder dit lesthema bundelen we verschillende activiteiten waarin de basisprincipes van artificiële intelligentie (AI) aan bod komen. Leerlingen leren wat AI is, hoe het werkt en hoe het kan worden toegepast in verschillende domeinen." - contact: "" + description: 'Onder dit lesthema bundelen we verschillende activiteiten waarin de basisprincipes van artificiële intelligentie (AI) aan bod komen. Leerlingen leren wat AI is, hoe het werkt en hoe het kan worden toegepast in verschillende domeinen.' + contact: '' kiks: title: KI und Klima sub_title: KIKS - description: "Schülerinnen und Schüler der dritten Klasse (SO) erforschen, wie Pflanzen sich über ihre Spaltöffnungen an den Klimawandel anpassen. Dazu zählen sie diese Spaltöffnungen mit künstlicher Intelligenz und Bilderkennung." - contact: "" + description: 'Schülerinnen und Schüler der dritten Klasse (SO) erforschen, wie Pflanzen sich über ihre Spaltöffnungen an den Klimawandel anpassen. Dazu zählen sie diese Spaltöffnungen mit künstlicher Intelligenz und Bilderkennung.' + contact: '' teaser: https://www.youtube.com/embed/dO-E33G20co curricula_files: - - file_title: "Projektblatt KIKS" - file_info: "Dies ist ein kurzer Überblick über das KIKS-Projekt mit Projektstruktur und -merkmalen." - file_location: "/assets/files/kiks/projectfiche_kiks.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Die Anleitung - auch in gedruckter Version erhältlich" - file_info: "Wir möchten den Lehrern Hintergrundwissen über den Inhalt dieses Projekts vermitteln: den Klimawandel, die Biologie der Spaltöffnungen und die Art und Weise, wie Pflanzen sich über die Spaltöffnungen an den Klimawandel anpassen, die wissenschaftliche Forschung der UGent und des Plantentuin Meise, die Bürgerwissenschaft, was künstliche Intelligenz (KI) ist, die Geschichte von KI, ihre Anwendung und Ethik, die Prinzipien digitaler Bilder, die Mathematik hinter den Algorithmen und die Grundlagen der derzeit am häufigsten verwendeten KI-Techniken. Wir zeigen auch, wie wir mit KIKS im Unterricht gearbeitet haben." - file_location: "/assets/files/kiks/KIKS_handleiding_eerstedruk.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Ein Schülerkurs" - file_info: "Mit dem Schülerkurs geben wir ein Beispiel für einen möglichen, umfassenden Weg, den ein Lehrer mit den Schülern gehen kann. Der Weg umfasst den Klimawandel, die Biologie der Spaltöffnungen mit einer Mikroskopie-Aufgabe, die Art und Weise, wie Pflanzen sich über die Spaltöffnungen an den Klimawandel anpassen, die wissenschaftliche Forschung der UGent und des Plantentuin Meise, das Sammeln von Daten zur Schulung eines neuronalen Netzwerks, was künstliche Intelligenz (KI) ist, die Geschichte von KI, ihre Anwendung und Ethik, die Prinzipien digitaler Bilder, das Arbeiten mit Convolutional Neural Networks, die Mathematik hinter dem Perceptron-Algorithmus, das lineare und nicht-lineare Klassifizieren von Daten und die Grundlagen des maschinellen Lernens." - file_location: "/assets/files/kiks/KIKS_leerlingencursus_eerstedruk.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Die Lehrziele" - file_info: "Im Rahmen des KIKS-Projekts können viele Lehrziele erreicht werden. Der Lehrer entscheidet selbst, welche Lehrziele mit dem Projekt in Verbindung gebracht werden. Darüber hinaus bietet das Projekt viele Möglichkeiten, die Schüler aktiv und selbstständig lernen zu lassen und ICT-Kenntnisse zu vermitteln. KIKS kann auch verwendet werden, um eine Forschungsaufgabe zu entwickeln. In den Endzielen und Lehrplänen der verschiedenen Verbände finden sich viele Lehrziele, die KIKS mit Biologie, Geografie und Mathematik verknüpfen." - file_location: "/assets/files/kiks/Leerdoelen-KIKS.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Das Erstellen eines Nagellaktabdrucks eines Blattteils" - file_info: "Um die Anzahl der Spaltöffnungen auf einem Teil eines Blattes einer Pflanze zu kennen, betrachten wir die Blattoberfläche unter dem Mikroskop. Wir können dazu einen Teil der dünnen Cuticula des Blattes entfernen, aber bei einigen Pflanzen gelingt das nicht so gut, zum Beispiel aufgrund der Steifheit des Blattes. Dies kann jedoch aufgefangen werden, indem die gleiche Methode verwendet wird wie die Forscher des Plantentuin Meise, nämlich einen Abdruck eines Teils der Blattoberfläche mit transparentem Nagellack zu machen. Das mikroskopische Bild kann mit einem Smartphone fotografiert werden." - file_location: "https://vimeo.com/467062270" - file_icon_name: "play_arrow" - link_name: "Ansehen" + - file_title: 'Projektblatt KIKS' + file_info: 'Dies ist ein kurzer Überblick über das KIKS-Projekt mit Projektstruktur und -merkmalen.' + file_location: '/assets/files/kiks/projectfiche_kiks.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Die Anleitung - auch in gedruckter Version erhältlich' + file_info: 'Wir möchten den Lehrern Hintergrundwissen über den Inhalt dieses Projekts vermitteln: den Klimawandel, die Biologie der Spaltöffnungen und die Art und Weise, wie Pflanzen sich über die Spaltöffnungen an den Klimawandel anpassen, die wissenschaftliche Forschung der UGent und des Plantentuin Meise, die Bürgerwissenschaft, was künstliche Intelligenz (KI) ist, die Geschichte von KI, ihre Anwendung und Ethik, die Prinzipien digitaler Bilder, die Mathematik hinter den Algorithmen und die Grundlagen der derzeit am häufigsten verwendeten KI-Techniken. Wir zeigen auch, wie wir mit KIKS im Unterricht gearbeitet haben.' + file_location: '/assets/files/kiks/KIKS_handleiding_eerstedruk.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Ein Schülerkurs' + file_info: 'Mit dem Schülerkurs geben wir ein Beispiel für einen möglichen, umfassenden Weg, den ein Lehrer mit den Schülern gehen kann. Der Weg umfasst den Klimawandel, die Biologie der Spaltöffnungen mit einer Mikroskopie-Aufgabe, die Art und Weise, wie Pflanzen sich über die Spaltöffnungen an den Klimawandel anpassen, die wissenschaftliche Forschung der UGent und des Plantentuin Meise, das Sammeln von Daten zur Schulung eines neuronalen Netzwerks, was künstliche Intelligenz (KI) ist, die Geschichte von KI, ihre Anwendung und Ethik, die Prinzipien digitaler Bilder, das Arbeiten mit Convolutional Neural Networks, die Mathematik hinter dem Perceptron-Algorithmus, das lineare und nicht-lineare Klassifizieren von Daten und die Grundlagen des maschinellen Lernens.' + file_location: '/assets/files/kiks/KIKS_leerlingencursus_eerstedruk.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Die Lehrziele' + file_info: 'Im Rahmen des KIKS-Projekts können viele Lehrziele erreicht werden. Der Lehrer entscheidet selbst, welche Lehrziele mit dem Projekt in Verbindung gebracht werden. Darüber hinaus bietet das Projekt viele Möglichkeiten, die Schüler aktiv und selbstständig lernen zu lassen und ICT-Kenntnisse zu vermitteln. KIKS kann auch verwendet werden, um eine Forschungsaufgabe zu entwickeln. In den Endzielen und Lehrplänen der verschiedenen Verbände finden sich viele Lehrziele, die KIKS mit Biologie, Geografie und Mathematik verknüpfen.' + file_location: '/assets/files/kiks/Leerdoelen-KIKS.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Das Erstellen eines Nagellaktabdrucks eines Blattteils' + file_info: 'Um die Anzahl der Spaltöffnungen auf einem Teil eines Blattes einer Pflanze zu kennen, betrachten wir die Blattoberfläche unter dem Mikroskop. Wir können dazu einen Teil der dünnen Cuticula des Blattes entfernen, aber bei einigen Pflanzen gelingt das nicht so gut, zum Beispiel aufgrund der Steifheit des Blattes. Dies kann jedoch aufgefangen werden, indem die gleiche Methode verwendet wird wie die Forscher des Plantentuin Meise, nämlich einen Abdruck eines Teils der Blattoberfläche mit transparentem Nagellack zu machen. Das mikroskopische Bild kann mit einem Smartphone fotografiert werden.' + file_location: 'https://vimeo.com/467062270' + file_icon_name: 'play_arrow' + link_name: 'Ansehen' socialrobot: title: Sozialer Roboter sub_title: Robotik im Klassenzimmer - description: "Während Schülerinnen und Schüler der ersten Klasse (SO) einen sozialen Roboter basteln und programmieren, lernen sie komplexe Probleme durch computational thinking zu lösen. Auf spielerische Weise arbeiten sie an den neuen Endzielen für digitale Kompetenzen." + description: 'Während Schülerinnen und Schüler der ersten Klasse (SO) einen sozialen Roboter basteln und programmieren, lernen sie komplexe Probleme durch computational thinking zu lösen. Auf spielerische Weise arbeiten sie an den neuen Endzielen für digitale Kompetenzen.' contact: Fragen? Kontaktieren Sie uns unter team@aiopschool.be. Die Presse kann sich an Francis Wyffels wenden unter Francis@dwengo.org. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 curricula_files: - - file_title: "Projektblatt Sozialer Roboter" + - file_title: 'Projektblatt Sozialer Roboter' file_info: "Dies ist ein kurzer Überblick über das Projekt 'Sozialer Roboter' mit Projektstruktur und -merkmalen." - file_location: "/assets/files/socialrobot/projectfiche_socialerobot.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Collage sozialer Roboter" - file_info: "Die Roboter auf diesem Foto sind Arbeiten von Schülern der ersten Klasse der Sekundarstufe oder Prototypen." - file_location: "/assets/files/socialrobot/collage.png" - file_icon_name: "description" - link_name: "Download" + file_location: '/assets/files/socialrobot/projectfiche_socialerobot.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Collage sozialer Roboter' + file_info: 'Die Roboter auf diesem Foto sind Arbeiten von Schülern der ersten Klasse der Sekundarstufe oder Prototypen.' + file_location: '/assets/files/socialrobot/collage.png' + file_icon_name: 'description' + link_name: 'Download' - file_title: "Bausatz für das 'Sozialer Roboter'-Projekt" - file_info: "Möchten Sie, dass Ihre Schülerinnen und Schüler auch einen sozialen Roboter entwerfen und bauen? Das geht mit dem Bausatz von Dwengo vzw. Auf der Abbildung sehen Sie die aktuelle Zusammensetzung des Bausatzes. Interessiert? Kontaktieren Sie uns per E-Mail oder finden Sie weitere Informationen auf dieser Projektseite." - file_location: "/assets/files/socialrobot/constructiekit_socialerobot.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Vom Projekt zu den Endzielen" + file_info: 'Möchten Sie, dass Ihre Schülerinnen und Schüler auch einen sozialen Roboter entwerfen und bauen? Das geht mit dem Bausatz von Dwengo vzw. Auf der Abbildung sehen Sie die aktuelle Zusammensetzung des Bausatzes. Interessiert? Kontaktieren Sie uns per E-Mail oder finden Sie weitere Informationen auf dieser Projektseite.' + file_location: '/assets/files/socialrobot/constructiekit_socialerobot.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Vom Projekt zu den Endzielen' file_info: "Die Endziele, an denen gearbeitet werden kann, werden mit den verschiedenen Phasen des Projekts 'Sozialer Roboter' verknüpft." - file_location: "/assets/files/socialrobot/EindtermenAStroomSsocialeRobot.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Emotionsmaschine (unvollständig) - Computational Thinking (unplugged Aktivität)" - file_info: "Unplugged Aktivität" - file_location: "/assets/files/socialrobot/emotiemachine_gewoon_nl.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Emotionsmaschine (Aufgabe) - Computational Thinking (unplugged Aktivität)" - file_info: "Unplugged Aktivität" - file_location: "/assets/files/socialrobot/emotiemachine_gids.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Emotionsmaschine (vollständig) - Computational Thinking (unplugged Aktivität)" - file_info: "Unplugged Aktivität" - file_location: "/assets/files/socialrobot/emotiemachine_ingevuld_nl.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Emotionsmaschine mit LED-Matrix - Computational Thinking (unplugged Aktivität)" - file_info: "Unplugged Aktivität" - file_location: "/assets/files/socialrobot/emotiemachine_matrices_nl.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Lehrerhandbuch" - file_info: "Die gebündelten Handbücher, in denen die Verwendung des Dwenguino und der Sensoren und Aktuatoren erklärt wird." - file_location: "/assets/files/socialrobot/ficheboekje_lkn.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Handbücher für Schülerinnen und Schüler" - file_info: "In diesen Handbüchern wird die Verwendung des Dwenguino und der Sensoren und Aktuatoren erklärt." - file_location: "/assets/files/socialrobot/fichesSocialeRobot_lln.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Erstelle ein Gesicht - Computational Thinking (unplugged Aktivität)" - file_info: "Unplugged Aktivität" - file_location: "/assets/files/socialrobot/maakeengezicht_activiteit.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Aufgaben der Übungen im MOOC" - file_info: "Eine Übersicht über die Programmieraufgaben im MOOC." - file_location: "/assets/files/socialrobot/Opgaven_MOOC.pdf" - file_icon_name: "description" - link_name: "Download" + file_location: '/assets/files/socialrobot/EindtermenAStroomSsocialeRobot.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Emotionsmaschine (unvollständig) - Computational Thinking (unplugged Aktivität)' + file_info: 'Unplugged Aktivität' + file_location: '/assets/files/socialrobot/emotiemachine_gewoon_nl.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Emotionsmaschine (Aufgabe) - Computational Thinking (unplugged Aktivität)' + file_info: 'Unplugged Aktivität' + file_location: '/assets/files/socialrobot/emotiemachine_gids.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Emotionsmaschine (vollständig) - Computational Thinking (unplugged Aktivität)' + file_info: 'Unplugged Aktivität' + file_location: '/assets/files/socialrobot/emotiemachine_ingevuld_nl.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Emotionsmaschine mit LED-Matrix - Computational Thinking (unplugged Aktivität)' + file_info: 'Unplugged Aktivität' + file_location: '/assets/files/socialrobot/emotiemachine_matrices_nl.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Lehrerhandbuch' + file_info: 'Die gebündelten Handbücher, in denen die Verwendung des Dwenguino und der Sensoren und Aktuatoren erklärt wird.' + file_location: '/assets/files/socialrobot/ficheboekje_lkn.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Handbücher für Schülerinnen und Schüler' + file_info: 'In diesen Handbüchern wird die Verwendung des Dwenguino und der Sensoren und Aktuatoren erklärt.' + file_location: '/assets/files/socialrobot/fichesSocialeRobot_lln.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Erstelle ein Gesicht - Computational Thinking (unplugged Aktivität)' + file_info: 'Unplugged Aktivität' + file_location: '/assets/files/socialrobot/maakeengezicht_activiteit.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Aufgaben der Übungen im MOOC' + file_info: 'Eine Übersicht über die Programmieraufgaben im MOOC.' + file_location: '/assets/files/socialrobot/Opgaven_MOOC.pdf' + file_icon_name: 'description' + link_name: 'Download' - file_title: "Poster 'Sozialer Roboter'-Projekt" - file_info: "Das Poster zeigt die verschiedenen Aspekte des Projekts." - file_location: "/assets/files/socialrobot/posterSocialeRobot_nl_Qo4ANmV.pdf" - file_icon_name: "description" - link_name: "Download" + file_info: 'Das Poster zeigt die verschiedenen Aspekte des Projekts.' + file_location: '/assets/files/socialrobot/posterSocialeRobot_nl_Qo4ANmV.pdf' + file_icon_name: 'description' + link_name: 'Download' - file_title: "Handbuch 'Hallo Roboter!'" - file_info: "Mit diesem Lehrbuch bringen Sie Ihren eigenen sozialen Roboter zum Leben." - file_location: "/assets/files/socialrobot/handleiding_hallo_robot.pdf" - file_icon_name: "description" - link_name: "Download" + file_info: 'Mit diesem Lehrbuch bringen Sie Ihren eigenen sozialen Roboter zum Leben.' + file_location: '/assets/files/socialrobot/handleiding_hallo_robot.pdf' + file_icon_name: 'description' + link_name: 'Download' chatbot: title: Sprachtechnologie in der Schule sub_title: Mit einem Chatbot arbeiten - description: "Wo Sprache und Technologie aufeinandertreffen, entsteht das Gebiet des Natural Language Processing. Kann ein Computer Texte verstehen, übersetzen oder sogar schreiben? Kann ein Computer Emotionen erkennen? Schülerinnen und Schüler der zweiten und dritten Klasse (SO) lernen in diesem Paket alles darüber." + description: 'Wo Sprache und Technologie aufeinandertreffen, entsteht das Gebiet des Natural Language Processing. Kann ein Computer Texte verstehen, übersetzen oder sogar schreiben? Kann ein Computer Emotionen erkennen? Schülerinnen und Schüler der zweiten und dritten Klasse (SO) lernen in diesem Paket alles darüber.' contact: Fragen? Kontaktieren Sie uns unter team@aiopschool.be. Die Presse kann sich an Francis Wyffels wenden unter Francis@dwengo.org. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 curricula_files: - - file_title: "Projektblatt Chatbot" - file_info: "Dies ist ein kurzer Überblick über das Chatbot-Projekt mit Projektstruktur und -merkmalen." - file_location: "/assets/files/chatbot/projectfiche_chatbot.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "BrAInfood Chatbots" - file_info: "In diesem brAInfood - für Jugendliche konzipiert - gibt das Zentrum für Daten & Gesellschaft weitere Informationen zu Chatbots. Das brAInfood enthält eine fiktive Geschichte über Lotte, die mit einem Chatbot spricht und vermutlich Informationen über sie an Unternehmen weitergibt. Es werden auch einige Punkte zu Chatbots erläutert sowie einige Tipps für Jugendliche, um ihre (personenbezogenen) Daten besser zu schützen. Auf diese Weise möchten wir Jugendliche für die Funktionsweise von Chatbots sensibilisieren und sie dazu anregen, über die gesammelten Daten nachzudenken." - file_location: "/assets/files/chatbot/Brainfood13_Chatbots_NL.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "BrAInfood Personalisierte Nachrichten" - file_info: "In diesem brAInfood des Zentrums für Daten & Gesellschaft werden Tipps gegeben, wie Sie die Kontrolle über Ihren Nachrichten-Feed behalten können." - file_location: "/assets/files/chatbot/brainfoodaanbevelingnieuws.jpg" - file_icon_name: "description" - link_name: "Download" + - file_title: 'Projektblatt Chatbot' + file_info: 'Dies ist ein kurzer Überblick über das Chatbot-Projekt mit Projektstruktur und -merkmalen.' + file_location: '/assets/files/chatbot/projectfiche_chatbot.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'BrAInfood Chatbots' + file_info: 'In diesem brAInfood - für Jugendliche konzipiert - gibt das Zentrum für Daten & Gesellschaft weitere Informationen zu Chatbots. Das brAInfood enthält eine fiktive Geschichte über Lotte, die mit einem Chatbot spricht und vermutlich Informationen über sie an Unternehmen weitergibt. Es werden auch einige Punkte zu Chatbots erläutert sowie einige Tipps für Jugendliche, um ihre (personenbezogenen) Daten besser zu schützen. Auf diese Weise möchten wir Jugendliche für die Funktionsweise von Chatbots sensibilisieren und sie dazu anregen, über die gesammelten Daten nachzudenken.' + file_location: '/assets/files/chatbot/Brainfood13_Chatbots_NL.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'BrAInfood Personalisierte Nachrichten' + file_info: 'In diesem brAInfood des Zentrums für Daten & Gesellschaft werden Tipps gegeben, wie Sie die Kontrolle über Ihren Nachrichten-Feed behalten können.' + file_location: '/assets/files/chatbot/brainfoodaanbevelingnieuws.jpg' + file_icon_name: 'description' + link_name: 'Download' - file_title: "Handbuch 'Chatbot' - Auch in gedruckter Form erhältlich" file_info: "Lehrkräfte erhalten über dieses Handbuch ausreichend Hintergrundinformationen, um mit (einem Teil des) Projekts 'Chatbot' im Klassenzimmer zu arbeiten. Das Buch behandelt verschiedene Aspekte der Sprachtechnologie, wie die Geschichte der künstlichen Intelligenz, ethische Aspekte, Sentimentanalyse und Cybermobbingerkennung, Chatbots, sprechende digitale Assistenten und Autorenerkennung. Es wird auch auf die STEM-Endziele sowie die Endziele zu digitaler Kompetenz und Medienkompetenz eingegangen." - file_location: "/assets/files/chatbot/Chatbot_handleiding_eerstedruk.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Improbotics - Lehrermappe - Lehrerfassung" - file_info: "In der Theateraufführung Improbotics improvisiert ein sozialer Roboter in den Szenen mit. In der Mappe für Lehrkräfte finden Sie Informationen zu den verwendeten Technologien." - file_location: "/assets/files/chatbot/Improbotics_lesmap_Leerkracht.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Improbotics - Lehrermappe - Schülerinnen und Schüler" - file_info: "In der Theateraufführung Improbotics improvisiert ein sozialer Roboter in den Szenen mit. In der Mappe finden Sie Informationen zu den verwendeten Technologien." - file_location: "/assets/files/chatbot/Improbotics_lesmap_Leerling.pdf" - file_icon_name: "description" - link_name: "Download" + file_location: '/assets/files/chatbot/Chatbot_handleiding_eerstedruk.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Improbotics - Lehrermappe - Lehrerfassung' + file_info: 'In der Theateraufführung Improbotics improvisiert ein sozialer Roboter in den Szenen mit. In der Mappe für Lehrkräfte finden Sie Informationen zu den verwendeten Technologien.' + file_location: '/assets/files/chatbot/Improbotics_lesmap_Leerkracht.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Improbotics - Lehrermappe - Schülerinnen und Schüler' + file_info: 'In der Theateraufführung Improbotics improvisiert ein sozialer Roboter in den Szenen mit. In der Mappe finden Sie Informationen zu den verwendeten Technologien.' + file_location: '/assets/files/chatbot/Improbotics_lesmap_Leerling.pdf' + file_icon_name: 'description' + link_name: 'Download' care: title: KI im Gesundheitswesen sub_title: KI-Systeme, die im Gesundheitswesen helfen - description: "Krankenhäuser machen bereits heute Gebrauch von künstlicher Intelligenz. Schülerinnen und Schüler der zweiten und dritten Klasse (SO) entdecken, welche Systeme existieren und wie sie Ärzte bei Entscheidungen unterstützen. Auf diese Weise lernen die Schülerinnen und Schüler die Prinzipien des Entscheidungsbaums, einer weit verbreiteten Technik im maschinellen Lernen." - contact: "" + description: 'Krankenhäuser machen bereits heute Gebrauch von künstlicher Intelligenz. Schülerinnen und Schüler der zweiten und dritten Klasse (SO) entdecken, welche Systeme existieren und wie sie Ärzte bei Entscheidungen unterstützen. Auf diese Weise lernen die Schülerinnen und Schüler die Prinzipien des Entscheidungsbaums, einer weit verbreiteten Technik im maschinellen Lernen.' + contact: '' teaser: https://www.youtube.com/embed/dO-E33G20co curricula_files: - - file_title: "Projektblatt KI im Gesundheitswesen" - file_info: "Dies ist ein kurzer Überblick über das Projekt KI im Gesundheitswesen mit Projektstruktur und -merkmalen." - file_location: "/assets/files/care/projectfiche_aiindezorg.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Sprouts" + - file_title: 'Projektblatt KI im Gesundheitswesen' + file_info: 'Dies ist ein kurzer Überblick über das Projekt KI im Gesundheitswesen mit Projektstruktur und -merkmalen.' + file_location: '/assets/files/care/projectfiche_aiindezorg.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Sprouts' file_info: "Ein Spiel zur Einführung in 'Graphen'." - file_location: "/assets/files/care/Sprouts.mov" - file_icon_name: "play_arrow" - link_name: "Download" - - file_title: "Erklärung zu Übungen mit Graphen aus dem Schülerkurs" - file_info: "Welche Figuren repräsentieren denselben Graphen? Eine formalere Methode." - file_location: "/assets/files/care/dezelfdegraafFormeel.mov" - file_icon_name: "play_arrow" - link_name: "Download" - - file_title: "Erklärung zu Übungen mit Graphen aus dem Schülerkurs" - file_info: "Welche Figuren repräsentieren denselben Graphen? Eine Methode mit Farben." - file_location: "/assets/files/care/dezelfdeGraaf.mov" - file_icon_name: "play_arrow" - link_name: "Download" - - file_title: "Der Schülerkurs - Ziel Durchfluss" - file_info: "Schülerkurs" - file_location: "/assets/files/care/AIindeZorg_doorstroom_eerstedruk.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Kartenset - Auch in gedruckter Form erhältlich" - file_info: "Mit diesem Kartenset können Lehrer die Schüler über ethische Aspekte neuer Technologien nachdenken lassen. Wie steht es um die Privatsphäre? Werden soziale Kontakte beeinträchtigt? Welche Technologien werden begeistert aufgenommen? Was ist nicht wünschenswert? Sind die neuen Technologien für alle erschwinglich?" - file_location: "/assets/files/care/Kaartset_AIIndeZorg_AIOpSchool_Dwengo.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Anleitung für das Kartenset" - file_info: "Diese Anleitung bietet zusätzliche Erläuterungen zum Kartenset." - file_location: "/assets/files/care/AIIndeZorgKaartenset_UitlegVoorLeerkracht.pdf" - file_icon_name: "description" - link_name: "Download" + file_location: '/assets/files/care/Sprouts.mov' + file_icon_name: 'play_arrow' + link_name: 'Download' + - file_title: 'Erklärung zu Übungen mit Graphen aus dem Schülerkurs' + file_info: 'Welche Figuren repräsentieren denselben Graphen? Eine formalere Methode.' + file_location: '/assets/files/care/dezelfdegraafFormeel.mov' + file_icon_name: 'play_arrow' + link_name: 'Download' + - file_title: 'Erklärung zu Übungen mit Graphen aus dem Schülerkurs' + file_info: 'Welche Figuren repräsentieren denselben Graphen? Eine Methode mit Farben.' + file_location: '/assets/files/care/dezelfdeGraaf.mov' + file_icon_name: 'play_arrow' + link_name: 'Download' + - file_title: 'Der Schülerkurs - Ziel Durchfluss' + file_info: 'Schülerkurs' + file_location: '/assets/files/care/AIindeZorg_doorstroom_eerstedruk.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Kartenset - Auch in gedruckter Form erhältlich' + file_info: 'Mit diesem Kartenset können Lehrer die Schüler über ethische Aspekte neuer Technologien nachdenken lassen. Wie steht es um die Privatsphäre? Werden soziale Kontakte beeinträchtigt? Welche Technologien werden begeistert aufgenommen? Was ist nicht wünschenswert? Sind die neuen Technologien für alle erschwinglich?' + file_location: '/assets/files/care/Kaartset_AIIndeZorg_AIOpSchool_Dwengo.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Anleitung für das Kartenset' + file_info: 'Diese Anleitung bietet zusätzliche Erläuterungen zum Kartenset.' + file_location: '/assets/files/care/AIIndeZorgKaartenset_UitlegVoorLeerkracht.pdf' + file_icon_name: 'description' + link_name: 'Download' - file_title: "Entscheidungsbaum 'mBrAIn'-Projekt in nicht kompakter Form" file_info: "Im Forschungsprojekt 'mBrain', das die Entwicklung einer App zum Vorhersagen eines Migräneanfalls zum Ziel hat, wurde ein Entscheidungsbaum erstellt. Mit diesem Entscheidungsbaum wird ein Problem der binären Klassifikation angegangen: Es gibt nur zwei Klassen: 'Migräne' und 'Keine Migräne'. (Quellen: Femke Ongenae. (2021), UGent; Van Hoecke, S., Ongenae, F., Paemeleire, K., & Vandenbussche, N. (2020). App muss Kopfschmerzen vorhersagen. EOS Wissenschaftsspezial, Technologie und Gesundheit, 25.) Wir haben die Form dieses Entscheidungsbaums in einen binären Entscheidungsbaum umgewandelt, um zu zeigen, dass diese Form nicht immer benutzerfreundlich ist. Weitere Informationen finden Sie im vierten Kapitel des Schülerkurses dieses Projekts." - file_location: "/assets/files/care/MBrainBeslissingsboom.png" - file_icon_name: "description" - link_name: "Download" - - file_title: "Suche nach Sprache - Computerdenken (unplugged Aktivität)" - file_info: "Das Locked-In-Syndrom ist eine der schlimmsten medizinischen Erkrankungen. Man ist vollständig gelähmt, außer dass man vielleicht noch mit einem Auge blinzeln kann. Der intelligente Geist ist in einem nutzlosen Körper eingesperrt: Man kann alles fühlen, aber nicht kommunizieren. Es kann jedem passieren, aus dem Nichts, als Folge eines Schlaganfalls. Wenn Sie Menschen mit dem Locked-In-Syndrom helfen möchten, ist es besser, Arzt oder Krankenschwester zu werden? Oder kann man als Informatiker auch helfen?" - file_location: "/assets/files/care/ZoektochtNaarSpraak.pdf" - file_icon_name: "description" - link_name: "Download" + file_location: '/assets/files/care/MBrainBeslissingsboom.png' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Suche nach Sprache - Computerdenken (unplugged Aktivität)' + file_info: 'Das Locked-In-Syndrom ist eine der schlimmsten medizinischen Erkrankungen. Man ist vollständig gelähmt, außer dass man vielleicht noch mit einem Auge blinzeln kann. Der intelligente Geist ist in einem nutzlosen Körper eingesperrt: Man kann alles fühlen, aber nicht kommunizieren. Es kann jedem passieren, aus dem Nichts, als Folge eines Schlaganfalls. Wenn Sie Menschen mit dem Locked-In-Syndrom helfen möchten, ist es besser, Arzt oder Krankenschwester zu werden? Oder kann man als Informatiker auch helfen?' + file_location: '/assets/files/care/ZoektochtNaarSpraak.pdf' + file_icon_name: 'description' + link_name: 'Download' stem: title: Python in MINT sub_title: Datavisualisierungen mit Python - description: "In diesem Paket lernen Sie, komplexe Probleme einfacher und schneller mit der Programmiersprache Python zu lösen. Programmieren kann nämlich eine verbindende Rolle zwischen Wissenschaft, Technik, Design und angewandter Mathematik spielen. Kurz gesagt, dank Python holen wir das Beste aus MINT heraus." + description: 'In diesem Paket lernen Sie, komplexe Probleme einfacher und schneller mit der Programmiersprache Python zu lösen. Programmieren kann nämlich eine verbindende Rolle zwischen Wissenschaft, Technik, Design und angewandter Mathematik spielen. Kurz gesagt, dank Python holen wir das Beste aus MINT heraus.' contact: Fragen? Kontaktieren Sie uns unter team@aiopschool.be. Die Presse kann sich an Francis Wyffels unter Francis@dwengo.org wenden. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 agriculture: title: KI in der Landwirtschaft sub_title: KI in der Landwirtschaft - description: "Verfaulte Tomaten während der Ernte entfernen? Künstliche Intelligenz kann dabei helfen. Aber wie? Schülerinnen und Schüler der zweiten und dritten Klasse (SO) setzen KI ein. Vielleicht kann ein vibrierendes Laufband das System noch verbessern?" + description: 'Verfaulte Tomaten während der Ernte entfernen? Künstliche Intelligenz kann dabei helfen. Aber wie? Schülerinnen und Schüler der zweiten und dritten Klasse (SO) setzen KI ein. Vielleicht kann ein vibrierendes Laufband das System noch verbessern?' contact: Fragen? Kontaktieren Sie uns unter team@aiopschool.be. Die Presse kann sich an Francis Wyffels unter Francis@dwengo.org wenden. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 curricula_files: - - file_title: "Design" - file_info: "Design des Laufbands" - file_location: "/assets/files/art/Transportband_InnoVET_RCH.zip" - file_icon_name: "description" - link_name: "Download" + - file_title: 'Design' + file_info: 'Design des Laufbands' + file_location: '/assets/files/art/Transportband_InnoVET_RCH.zip' + file_icon_name: 'description' + link_name: 'Download' art: title: KI in der Kunst sub_title: Zeichenroboter im Unterricht - description: "Können wir Kunst mit künstlicher Intelligenz schaffen? Schülerinnen und Schüler der zweiten und dritten Klasse (SO) setzen sich kreativ mit KI auseinander und reflektieren über das Ergebnis. Ist das Kunst? Sie entdecken auch, wie KI unser kulturelles Erbe schützen kann." - contact: "" + description: 'Können wir Kunst mit künstlicher Intelligenz schaffen? Schülerinnen und Schüler der zweiten und dritten Klasse (SO) setzen sich kreativ mit KI auseinander und reflektieren über das Ergebnis. Ist das Kunst? Sie entdecken auch, wie KI unser kulturelles Erbe schützen kann.' + contact: '' teaser: https://www.youtube.com/embed/dO-E33G20co wegostem: title: WeGoSTEM sub_title: Zeichenroboter im Unterricht - description: "Wir fordern Kinder der dritten Klasse (GS) heraus, einen zeichnenden Kunstroboter zu programmieren. Spielerisch lernen die Kinder viele MINT-Fähigkeiten, von Technik bis zum algorithmischen Denken." + description: 'Wir fordern Kinder der dritten Klasse (GS) heraus, einen zeichnenden Kunstroboter zu programmieren. Spielerisch lernen die Kinder viele MINT-Fähigkeiten, von Technik bis zum algorithmischen Denken.' contact: Fragen? Kontaktieren Sie uns unter team@aiopschool.be. Die Presse kann sich an Francis Wyffels unter Francis@dwengo.org wenden. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 computational_thinking: title: Algorithmisches Denken sub_title: Algorithmisches Denken im Unterricht - description: "Wie können wir komplexe Probleme mithilfe eines Computers lösen? Dank algorithmischem Denken! Das können Sie durch verschiedene Aktivitäten mit oder ohne Computer lernen. Wir helfen Ihnen gerne auf dem Weg." + description: 'Wie können wir komplexe Probleme mithilfe eines Computers lösen? Dank algorithmischem Denken! Das können Sie durch verschiedene Aktivitäten mit oder ohne Computer lernen. Wir helfen Ihnen gerne auf dem Weg.' contact: Fragen? Kontaktieren Sie uns unter team@aiopschool.be. Die Presse kann sich an Francis Wyffels unter Francis@dwengo.org wenden. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 curricula_files: - - file_title: "Konzepte und Ansätze des algorithmischen Denkens" - file_info: "Poster​" - file_location: "/assets/files/computational_thinking/CDposterDwengo2.png" - file_icon_name: "description" - link_name: "Download" - - file_title: "Erklärung der vier Konzepte des algorithmischen Denkens" - file_info: "Präsentation über die vier Konzepte des algorithmischen Denkens: Dekomposition, Mustererkennung, Abstraktion und Algorithmus. Sie können die PDF herunterladen > öffnen > präsentieren über CTRL-L und mit den Pfeiltasten navigieren." - file_location: "/assets/files/computational_thinking/CD4concepten_33V3gBg.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Konzepte und Prinzipien" - file_info: "Übersicht​" - file_location: "/assets/files/computational_thinking/Icoontjes.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged-Aktivität - Emotionsmaschine (Aufgabe)" - file_info: "Wie können Sie Emotionen bei einem Roboter fördern?​" - file_location: "/assets/files/computational_thinking/emotiemachine_gids.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged-Aktivität - Emotionsmaschine" - file_info: "Wie können Sie Emotionen bei einem Roboter fördern?​" - file_location: "/assets/files/computational_thinking/emotiemachine_gewoon_nl.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged-Aktivität - Farben nach Zahlen" + - file_title: 'Konzepte und Ansätze des algorithmischen Denkens' + file_info: 'Poster​' + file_location: '/assets/files/computational_thinking/CDposterDwengo2.png' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Erklärung der vier Konzepte des algorithmischen Denkens' + file_info: 'Präsentation über die vier Konzepte des algorithmischen Denkens: Dekomposition, Mustererkennung, Abstraktion und Algorithmus. Sie können die PDF herunterladen > öffnen > präsentieren über CTRL-L und mit den Pfeiltasten navigieren.' + file_location: '/assets/files/computational_thinking/CD4concepten_33V3gBg.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Konzepte und Prinzipien' + file_info: 'Übersicht​' + file_location: '/assets/files/computational_thinking/Icoontjes.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged-Aktivität - Emotionsmaschine (Aufgabe)' + file_info: 'Wie können Sie Emotionen bei einem Roboter fördern?​' + file_location: '/assets/files/computational_thinking/emotiemachine_gids.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged-Aktivität - Emotionsmaschine' + file_info: 'Wie können Sie Emotionen bei einem Roboter fördern?​' + file_location: '/assets/files/computational_thinking/emotiemachine_gewoon_nl.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged-Aktivität - Farben nach Zahlen' file_info: "​Bilder können auf verschiedene Weisen dargestellt werden. Bei diesem Farben-nach-Zahlen-Rätsel müssen Sie ein Bild rekonstruieren, indem Sie die gegebene Liste von Zahlen verwenden. Diese Liste sagt Ihnen, welche Farbe Sie jedem Quadrat ('Pixel') zuordnen." - file_location: "/assets/files/computational_thinking/kleurenopnummer1.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged-Aktivität - Ein menschliches Computernetzwerk" - file_info: "In dieser Aktivität lernen die Schülerinnen und Schüler, wie die Datenübertragung im Internet funktioniert. Computer, Smartphones und andere Geräte, die über das Internet miteinander verbunden sind, können kommunizieren. Um sich gegenseitig zu verstehen, muss diese Kommunikation nach bestimmten Regeln erfolgen. Diese Regeln nennen wir Protokoll.​" - file_location: "/assets/files/computational_thinking/menselijkComputernetwerk.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged-Aktivität - Komprimierung" - file_info: "Um Bilder über Netzwerke zu senden, möchten wir die Informationen mit möglichst wenig Daten darstellen. Hier kommt die Komprimierung ins Spiel. Mit Hilfe von Algorithmen werden Bilder mit möglichst wenigen Zahlen dargestellt, aber so, dass Sie das ursprüngliche Bild immer noch wiederherstellen können. Andere Algorithmen stellen das ursprüngliche Bild wieder her, wenn die Informationen ihr Ziel erreicht haben.​" - file_location: "/assets/files/computational_thinking/puzzel-gecomprimeerdepixel11.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged-Aktivität - Programmieren Sie einmal einen Menschen" - file_info: "Computer können nicht interpretieren und führen daher buchstäblich jede Anweisung aus, die Sie ihnen geben. Die Herausforderung für den Programmierer besteht darin, Probleme in kleine, vom Computer ausführbare Schritte zu zerlegen und dem Computer die Anweisungen auf die richtige Weise zu geben.​" - file_location: "/assets/files/computational_thinking/programmeerEensEenMens.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged-Aktivität - Suche nach Sprache" - file_info: "Das Locked-In-Syndrom ist eine der schlimmsten medizinischen Erkrankungen. Sie sind vollständig gelähmt, außer dass Sie vielleicht noch mit einem Auge blinzeln können. Ihr intelligenter Geist ist in einem nutzlosen Körper gefangen: Sie können alles fühlen, aber nicht kommunizieren. Es kann jedem passieren, aus dem Nichts, als Folge eines Schlaganfalls. Wenn Sie Menschen mit dem Locked-In-Syndrom helfen möchten, werden Sie am besten Arzt oder Krankenschwester? Oder kann Ihnen auch ein Informatiker helfen?​" - file_location: "/assets/files/computational_thinking/ZoektochtNaarSpraak.pdf" - file_icon_name: "description" - link_name: "Download" + file_location: '/assets/files/computational_thinking/kleurenopnummer1.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged-Aktivität - Ein menschliches Computernetzwerk' + file_info: 'In dieser Aktivität lernen die Schülerinnen und Schüler, wie die Datenübertragung im Internet funktioniert. Computer, Smartphones und andere Geräte, die über das Internet miteinander verbunden sind, können kommunizieren. Um sich gegenseitig zu verstehen, muss diese Kommunikation nach bestimmten Regeln erfolgen. Diese Regeln nennen wir Protokoll.​' + file_location: '/assets/files/computational_thinking/menselijkComputernetwerk.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged-Aktivität - Komprimierung' + file_info: 'Um Bilder über Netzwerke zu senden, möchten wir die Informationen mit möglichst wenig Daten darstellen. Hier kommt die Komprimierung ins Spiel. Mit Hilfe von Algorithmen werden Bilder mit möglichst wenigen Zahlen dargestellt, aber so, dass Sie das ursprüngliche Bild immer noch wiederherstellen können. Andere Algorithmen stellen das ursprüngliche Bild wieder her, wenn die Informationen ihr Ziel erreicht haben.​' + file_location: '/assets/files/computational_thinking/puzzel-gecomprimeerdepixel11.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged-Aktivität - Programmieren Sie einmal einen Menschen' + file_info: 'Computer können nicht interpretieren und führen daher buchstäblich jede Anweisung aus, die Sie ihnen geben. Die Herausforderung für den Programmierer besteht darin, Probleme in kleine, vom Computer ausführbare Schritte zu zerlegen und dem Computer die Anweisungen auf die richtige Weise zu geben.​' + file_location: '/assets/files/computational_thinking/programmeerEensEenMens.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged-Aktivität - Suche nach Sprache' + file_info: 'Das Locked-In-Syndrom ist eine der schlimmsten medizinischen Erkrankungen. Sie sind vollständig gelähmt, außer dass Sie vielleicht noch mit einem Auge blinzeln können. Ihr intelligenter Geist ist in einem nutzlosen Körper gefangen: Sie können alles fühlen, aber nicht kommunizieren. Es kann jedem passieren, aus dem Nichts, als Folge eines Schlaganfalls. Wenn Sie Menschen mit dem Locked-In-Syndrom helfen möchten, werden Sie am besten Arzt oder Krankenschwester? Oder kann Ihnen auch ein Informatiker helfen?​' + file_location: '/assets/files/computational_thinking/ZoektochtNaarSpraak.pdf' + file_icon_name: 'description' + link_name: 'Download' math_with_python: title: Python im Mathematikunterricht sub_title: Python in der Mathematik - description: "Die Programmiersprache Python bietet interessante Möglichkeiten, den Mathematikunterricht zu bereichern. Von der Pythagoras-Theorie bis zur Erstellung eigener Grafiken, digitalen Bildverarbeitung und linearer Regression wird alles mit Python klarer." - contact: "" + description: 'Die Programmiersprache Python bietet interessante Möglichkeiten, den Mathematikunterricht zu bereichern. Von der Pythagoras-Theorie bis zur Erstellung eigener Grafiken, digitalen Bildverarbeitung und linearer Regression wird alles mit Python klarer.' + contact: '' teaser: https://www.youtube.com/embed/dO-E33G20co python_programming: title: Programmieren mit Python sub_title: Grundlagen des Programmierens in Python - description: "Die Grundprinzipien des Programmierens erlernen? Das ist perfekt möglich mit diesem Paket. Wir verwenden Python und lernen alles über Sequenzen, Wiederholungsstrukturen und Auswahlstrukturen. Genau das steht in den Endzielen. Und noch mehr!" + description: 'Die Grundprinzipien des Programmierens erlernen? Das ist perfekt möglich mit diesem Paket. Wir verwenden Python und lernen alles über Sequenzen, Wiederholungsstrukturen und Auswahlstrukturen. Genau das steht in den Endzielen. Und noch mehr!' contact: Fragen? Kontaktieren Sie uns unter team@aiopschool.be. Die Presse kann sich an Francis Wyffels unter Francis@dwengo.org wenden. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 physical_computing: title: Physical Computing sub_title: Programmieren von Robotern im Unterricht - description: "Ein Musikinstrument, Auto oder Wetterstation bauen? Das geht mit Dwenguino, einer Mikrocontroller-Plattform mit einer eigenen Programmierumgebung. Schülerinnen und Schüler der Grundschule und der Sekundarstufe können sofort damit arbeiten. Echt oder in unserem Simulator, blockbasiert oder textuell." + description: 'Ein Musikinstrument, Auto oder Wetterstation bauen? Das geht mit Dwenguino, einer Mikrocontroller-Plattform mit einer eigenen Programmierumgebung. Schülerinnen und Schüler der Grundschule und der Sekundarstufe können sofort damit arbeiten. Echt oder in unserem Simulator, blockbasiert oder textuell.' contact: Fragen? Kontaktieren Sie uns unter team@aiopschool.be. Die Presse kann sich an Francis Wyffels unter Francis@dwengo.org wenden. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 curricula_files: - - file_title: "Bouw jouw eigen robot" - file_info: "Baue deinen eigenen fahrenden Roboter." - file_location: "/assets/files/physical_computing/bouwjouweigenrobot.pdf" - file_icon_name: "description" - link_name: "Download" + - file_title: 'Bouw jouw eigen robot' + file_info: 'Baue deinen eigenen fahrenden Roboter.' + file_location: '/assets/files/physical_computing/bouwjouweigenrobot.pdf' + file_icon_name: 'description' + link_name: 'Download' diff --git a/backend/_i18n/en.yml b/backend/_i18n/en.yml index 60164f92..f7778448 100644 --- a/backend/_i18n/en.yml +++ b/backend/_i18n/en.yml @@ -7,212 +7,212 @@ curricula_page: algorithms: title: Algorithms sub_title: Algorithms - description: "Students in the second and third grade (secondary education) learn how to use algorithms to solve problems. They learn how to design algorithms and analyze the efficiency of algorithms. They also learn how to use algorithms to solve problems." - contact: "" + description: 'Students in the second and third grade (secondary education) learn how to use algorithms to solve problems. They learn how to design algorithms and analyze the efficiency of algorithms. They also learn how to use algorithms to solve problems.' + contact: '' teaser: https://www.youtube.com/embed/2B6gZ9HdQ1Y basics_ai: title: Basisprincipes van AI sub_title: Basisprincipes van AI - description: "Onder dit lesthema bundelen we verschillende activiteiten waarin de basisprincipes van artificiële intelligentie (AI) aan bod komen. Leerlingen leren wat AI is, hoe het werkt en hoe het kan worden toegepast in verschillende domeinen." - contact: "" + description: 'Onder dit lesthema bundelen we verschillende activiteiten waarin de basisprincipes van artificiële intelligentie (AI) aan bod komen. Leerlingen leren wat AI is, hoe het werkt en hoe het kan worden toegepast in verschillende domeinen.' + contact: '' kiks: title: AI and Climate sub_title: KIKS - description: "Students in the third grade (SO) investigate how plants adapt to climate change through their stomata. They use artificial intelligence and image recognition to count these stomata." - contact: "" + description: 'Students in the third grade (SO) investigate how plants adapt to climate change through their stomata. They use artificial intelligence and image recognition to count these stomata.' + contact: '' teaser: https://www.youtube.com/embed/dO-E33G20co curricula_files: - - file_title: "Project Sheet KIKS" - file_info: "This is a brief overview of the KIKS project with project structure and characteristics." - file_location: "/assets/files/kiks/projectfiche_kiks.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "The manual - also available in print" - file_info: "We want to provide teachers with background knowledge about the content of this project: climate change, the biology of stomata, how plants adapt to climate change through stomata, the scientific research of UGent and Plantentuin Meise underlying this project, citizen science, what artificial intelligence (AI) is, the history of AI, its use and ethics, principles of digital images, mathematics behind algorithms, and foundations of currently most-used AI techniques. We also explain how we implemented KIKS in the classroom." - file_location: "/assets/files/kiks/KIKS_handleiding_eerstedruk.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Student Course" - file_info: "With the student course, we provide an example of a possible, comprehensive trajectory that a teacher can go through with students. The trajectory includes climate change, the biology of stomata with a microscopy assignment, how plants adapt to climate change through stomata, the scientific research of UGent and Plantentuin Meise, collecting data to train a neural network, what artificial intelligence (AI) is, the history of AI, its use and ethics, principles of digital images, working with convolutions, mathematics behind the Perceptron algorithm, linear and non-linear classification of data, and foundations of machine learning." - file_location: "/assets/files/kiks/KIKS_leerlingencursus_eerstedruk.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Curriculum Goals" - file_info: "Within the KIKS project, many curriculum goals can be addressed. The teacher determines which goals are related to the project. Moreover, the project offers many opportunities to actively engage and let students learn independently, as well as teach ICT skills. KIKS can also be used for a research assignment. In the final objectives and curricula of various educational bodies, many goals can be found linking KIKS with biology, geography, and mathematics." - file_location: "/assets/files/kiks/Leerdoelen-KIKS.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Making a Nail Polish Impression of a Leaf Part" - file_info: "To know the number of stomata on a part of a plant leaf, we examine the leaf surface under the microscope. We can remove a piece of the thin cuticle of the leaf for this, but for some plants, it is not so successful, for example, due to the stiffness of the leaf. However, this can be compensated by using the same method as the researchers at Plantentuin Meise, namely, taking an impression of a part of the leaf surface with transparent nail polish. The microscopic image can be photographed with a smartphone." - file_location: "https://vimeo.com/467062270" - file_icon_name: "play_arrow" - link_name: "Watch" + - file_title: 'Project Sheet KIKS' + file_info: 'This is a brief overview of the KIKS project with project structure and characteristics.' + file_location: '/assets/files/kiks/projectfiche_kiks.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'The manual - also available in print' + file_info: 'We want to provide teachers with background knowledge about the content of this project: climate change, the biology of stomata, how plants adapt to climate change through stomata, the scientific research of UGent and Plantentuin Meise underlying this project, citizen science, what artificial intelligence (AI) is, the history of AI, its use and ethics, principles of digital images, mathematics behind algorithms, and foundations of currently most-used AI techniques. We also explain how we implemented KIKS in the classroom.' + file_location: '/assets/files/kiks/KIKS_handleiding_eerstedruk.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Student Course' + file_info: 'With the student course, we provide an example of a possible, comprehensive trajectory that a teacher can go through with students. The trajectory includes climate change, the biology of stomata with a microscopy assignment, how plants adapt to climate change through stomata, the scientific research of UGent and Plantentuin Meise, collecting data to train a neural network, what artificial intelligence (AI) is, the history of AI, its use and ethics, principles of digital images, working with convolutions, mathematics behind the Perceptron algorithm, linear and non-linear classification of data, and foundations of machine learning.' + file_location: '/assets/files/kiks/KIKS_leerlingencursus_eerstedruk.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Curriculum Goals' + file_info: 'Within the KIKS project, many curriculum goals can be addressed. The teacher determines which goals are related to the project. Moreover, the project offers many opportunities to actively engage and let students learn independently, as well as teach ICT skills. KIKS can also be used for a research assignment. In the final objectives and curricula of various educational bodies, many goals can be found linking KIKS with biology, geography, and mathematics.' + file_location: '/assets/files/kiks/Leerdoelen-KIKS.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Making a Nail Polish Impression of a Leaf Part' + file_info: 'To know the number of stomata on a part of a plant leaf, we examine the leaf surface under the microscope. We can remove a piece of the thin cuticle of the leaf for this, but for some plants, it is not so successful, for example, due to the stiffness of the leaf. However, this can be compensated by using the same method as the researchers at Plantentuin Meise, namely, taking an impression of a part of the leaf surface with transparent nail polish. The microscopic image can be photographed with a smartphone.' + file_location: 'https://vimeo.com/467062270' + file_icon_name: 'play_arrow' + link_name: 'Watch' socialrobot: title: Social Robot sub_title: Robotics in the classroom - description: "While first-year students (secondary education) build and program a social robot, they learn to solve complex problems through computational thinking. They playfully work on the new end terms for digital competencies." + description: 'While first-year students (secondary education) build and program a social robot, they learn to solve complex problems through computational thinking. They playfully work on the new end terms for digital competencies.' contact: Questions? Contact us at team@aiopschool.be. The press can contact Francis Wyffels via Francis@dwengo.org. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 curricula_files: - - file_title: "Project Sheet Social Robot" + - file_title: 'Project Sheet Social Robot' file_info: "This is a brief overview of the 'Social Robot' project with project structure and characteristics." - file_location: "/assets/files/socialrobot/projectfiche_socialerobot.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Collage of Social Robots" - file_info: "The robots in this photo are creations of first-year secondary education students or prototypes." - file_location: "/assets/files/socialrobot/collage.png" - file_icon_name: "description" - link_name: "Download" + file_location: '/assets/files/socialrobot/projectfiche_socialerobot.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Collage of Social Robots' + file_info: 'The robots in this photo are creations of first-year secondary education students or prototypes.' + file_location: '/assets/files/socialrobot/collage.png' + file_icon_name: 'description' + link_name: 'Download' - file_title: "Construction Kit for 'Social Robot' Project" - file_info: "Do you want your students to design and build a social robot too? This is possible via the construction kit of Dwengovzw. The figure shows the current composition of the construction kit. Interested? Contact us by email or find more information on this project page." - file_location: "/assets/files/socialrobot/constructiekit_socialerobot.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "From Project to End Terms" + file_info: 'Do you want your students to design and build a social robot too? This is possible via the construction kit of Dwengovzw. The figure shows the current composition of the construction kit. Interested? Contact us by email or find more information on this project page.' + file_location: '/assets/files/socialrobot/constructiekit_socialerobot.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'From Project to End Terms' file_info: "The end terms that can be worked on are linked to the different phases of the 'Social Robot' project." - file_location: "/assets/files/socialrobot/EindtermenAStroomSsocialeRobot.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Emotion Machine (Incomplete) - Computational Thinking (Unplugged Activity)" - file_info: "Unplugged activity" - file_location: "/assets/files/socialrobot/emotiemachine_gewoon_nl.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Emotion Machine (Task) - Computational Thinking (Unplugged Activity)" - file_info: "Unplugged activity" - file_location: "/assets/files/socialrobot/emotiemachine_gids.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Emotion Machine (Complete) - Computational Thinking (Unplugged Activity)" - file_info: "Unplugged activity" - file_location: "/assets/files/socialrobot/emotiemachine_ingevuld_nl.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Emotion Machine with LED Matrix - Computational Thinking (Unplugged Activity)" - file_info: "Unplugged activity" - file_location: "/assets/files/socialrobot/emotiemachine_matrices_nl.pdf" - file_icon_name: "description" - link_name: "Download" + file_location: '/assets/files/socialrobot/EindtermenAStroomSsocialeRobot.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Emotion Machine (Incomplete) - Computational Thinking (Unplugged Activity)' + file_info: 'Unplugged activity' + file_location: '/assets/files/socialrobot/emotiemachine_gewoon_nl.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Emotion Machine (Task) - Computational Thinking (Unplugged Activity)' + file_info: 'Unplugged activity' + file_location: '/assets/files/socialrobot/emotiemachine_gids.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Emotion Machine (Complete) - Computational Thinking (Unplugged Activity)' + file_info: 'Unplugged activity' + file_location: '/assets/files/socialrobot/emotiemachine_ingevuld_nl.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Emotion Machine with LED Matrix - Computational Thinking (Unplugged Activity)' + file_info: 'Unplugged activity' + file_location: '/assets/files/socialrobot/emotiemachine_matrices_nl.pdf' + file_icon_name: 'description' + link_name: 'Download' - file_title: "Teacher's Guide" - file_info: "The bundled sheets explain the use of the Dwenguino and the sensors and actuators." - file_location: "/assets/files/socialrobot/ficheboekje_lkn.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Information Sheets for Students" - file_info: "These information sheets explain the use of the Dwenguino and sensors and actuators." - file_location: "/assets/files/socialrobot/fichesSocialeRobot_lln.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Create a Face - Computational Thinking (Unplugged Activity)" - file_info: "Unplugged activity" - file_location: "/assets/files/socialrobot/maakeengezicht_activiteit.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Tasks for Exercises in the MOOC" - file_info: "An overview of programming exercises in the MOOC" - file_location: "/assets/files/socialrobot/Opgaven_MOOC.pdf" - file_icon_name: "description" - link_name: "Download" + file_info: 'The bundled sheets explain the use of the Dwenguino and the sensors and actuators.' + file_location: '/assets/files/socialrobot/ficheboekje_lkn.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Information Sheets for Students' + file_info: 'These information sheets explain the use of the Dwenguino and sensors and actuators.' + file_location: '/assets/files/socialrobot/fichesSocialeRobot_lln.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Create a Face - Computational Thinking (Unplugged Activity)' + file_info: 'Unplugged activity' + file_location: '/assets/files/socialrobot/maakeengezicht_activiteit.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Tasks for Exercises in the MOOC' + file_info: 'An overview of programming exercises in the MOOC' + file_location: '/assets/files/socialrobot/Opgaven_MOOC.pdf' + file_icon_name: 'description' + link_name: 'Download' - file_title: "Poster 'Social Robot' Project" - file_info: "The poster displays the different aspects of the project." - file_location: "/assets/files/socialrobot/posterSocialeRobot_nl_Qo4ANmV.pdf" - file_icon_name: "description" - link_name: "Download" + file_info: 'The poster displays the different aspects of the project.' + file_location: '/assets/files/socialrobot/posterSocialeRobot_nl_Qo4ANmV.pdf' + file_icon_name: 'description' + link_name: 'Download' - file_title: "Manual 'Hello Robot!'" - file_info: "With this lesson booklet, you bring your own social robot to life." - file_location: "/assets/files/socialrobot/handleiding_hallo_robot.pdf" - file_icon_name: "description" - link_name: "Download" + file_info: 'With this lesson booklet, you bring your own social robot to life.' + file_location: '/assets/files/socialrobot/handleiding_hallo_robot.pdf' + file_icon_name: 'description' + link_name: 'Download' chatbot: title: Language Technology at School sub_title: Getting Started with a Chatbot - description: "Where language and technology come together, the domain of Natural Language Processing emerges. Can a computer understand, translate, or even write texts? Can a computer recognize emotions? Students in the second and third grades (SO) learn all about it in this package." + description: 'Where language and technology come together, the domain of Natural Language Processing emerges. Can a computer understand, translate, or even write texts? Can a computer recognize emotions? Students in the second and third grades (SO) learn all about it in this package.' contact: Questions? Contact us at team@aiopschool.be. The press can contact Francis Wyffels via Francis@dwengo.org. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 curricula_files: - - file_title: "Project Sheet Chatbot" - file_info: "This is a brief overview of the Chatbot project with project structure and characteristics." - file_location: "/assets/files/chatbot/projectfiche_chatbot.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "BrAInfood Chatbots" - file_info: "In this BrAInfood - aimed at young people - the Knowledge Center Data & Society provides more information about chatbots. The BrAInfood includes a fictional story about Lotte talking to a chatbot and presumably providing information about her to companies. Further, some points related to chatbots are explained, along with some tips for young people to better protect their (personal) data. In this way, we aim to make young people more aware of how chatbots work and encourage them to reflect on the data collected about them." - file_location: "/assets/files/chatbot/Brainfood13_Chatbots_NL.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "BrAInfood Personalized Newsfeeds" - file_info: "In this BrAInfood from the Knowledge Center Data & Society, tips are given on how to keep control over your newsfeed." - file_location: "/assets/files/chatbot/brainfoodaanbevelingnieuws.jpg" - file_icon_name: "description" - link_name: "Download" + - file_title: 'Project Sheet Chatbot' + file_info: 'This is a brief overview of the Chatbot project with project structure and characteristics.' + file_location: '/assets/files/chatbot/projectfiche_chatbot.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'BrAInfood Chatbots' + file_info: 'In this BrAInfood - aimed at young people - the Knowledge Center Data & Society provides more information about chatbots. The BrAInfood includes a fictional story about Lotte talking to a chatbot and presumably providing information about her to companies. Further, some points related to chatbots are explained, along with some tips for young people to better protect their (personal) data. In this way, we aim to make young people more aware of how chatbots work and encourage them to reflect on the data collected about them.' + file_location: '/assets/files/chatbot/Brainfood13_Chatbots_NL.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'BrAInfood Personalized Newsfeeds' + file_info: 'In this BrAInfood from the Knowledge Center Data & Society, tips are given on how to keep control over your newsfeed.' + file_location: '/assets/files/chatbot/brainfoodaanbevelingnieuws.jpg' + file_icon_name: 'description' + link_name: 'Download' - file_title: "Manual 'Chatbot' - Also available in print" file_info: "Teachers acquire sufficient background information through this manual to work with (a part of) the 'Chatbot' project in the classroom. The book covers various aspects of language technology, such as the history of artificial intelligence, its ethical aspects, sentiment analysis, and cyberbullying detection, chatbots, speaking digital assistants, and author recognition. It also addresses the STEM objectives and the objectives related to digital competence and media literacy." - file_location: "/assets/files/chatbot/Chatbot_handleiding_eerstedruk.pdf" - file_icon_name: "description" - link_name: "Download" + file_location: '/assets/files/chatbot/Chatbot_handleiding_eerstedruk.pdf' + file_icon_name: 'description' + link_name: 'Download' - file_title: "Improbotics - Lesson Plan - Teacher's Version" - file_info: "In the theater performance Improbotics, a social robot improvises in the scenes. The lesson plan provides information about the technologies used." - file_location: "/assets/files/chatbot/Improbotics_lesmap_Leerkracht.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Improbotics - Lesson Plan - Students" - file_info: "In the theater performance Improbotics, a social robot improvises in the scenes. The lesson plan provides information about the technologies used." - file_location: "/assets/files/chatbot/Improbotics_lesmap_Leerling.pdf" - file_icon_name: "description" - link_name: "Download" + file_info: 'In the theater performance Improbotics, a social robot improvises in the scenes. The lesson plan provides information about the technologies used.' + file_location: '/assets/files/chatbot/Improbotics_lesmap_Leerkracht.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Improbotics - Lesson Plan - Students' + file_info: 'In the theater performance Improbotics, a social robot improvises in the scenes. The lesson plan provides information about the technologies used.' + file_location: '/assets/files/chatbot/Improbotics_lesmap_Leerling.pdf' + file_icon_name: 'description' + link_name: 'Download' care: title: AI in Healthcare sub_title: AI Systems Assisting in Healthcare - description: "Hospitals are already using artificial intelligence today. Students in the second and third grades (SO) discover the existing systems and how they help doctors make decisions. This way, students learn the principles of the decision tree, a commonly used technique in machine learning." - contact: "" + description: 'Hospitals are already using artificial intelligence today. Students in the second and third grades (SO) discover the existing systems and how they help doctors make decisions. This way, students learn the principles of the decision tree, a commonly used technique in machine learning.' + contact: '' teaser: https://www.youtube.com/embed/dO-E33G20co curricula_files: - - file_title: "Project Sheet AI in Healthcare" - file_info: "This is a brief overview of the AI in Healthcare project with project structure and characteristics." - file_location: "/assets/files/care/projectfiche_aiindezorg.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Sprouts" + - file_title: 'Project Sheet AI in Healthcare' + file_info: 'This is a brief overview of the AI in Healthcare project with project structure and characteristics.' + file_location: '/assets/files/care/projectfiche_aiindezorg.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Sprouts' file_info: "A game as an introduction to 'Graphs'." - file_location: "/assets/files/care/Sprouts.mov" - file_icon_name: "play_arrow" - link_name: "Download" - - file_title: "Explanation of Exercises on Graphs from the Student Course" - file_info: "Which figures represent the same graph? A more formal approach." - file_location: "/assets/files/care/dezelfdegraafFormeel.mov" - file_icon_name: "play_arrow" - link_name: "Download" - - file_title: "Explanation of Exercises on Graphs from the Student Course" - file_info: "Which figures represent the same graph? An approach with colors." - file_location: "/assets/files/care/dezelfdeGraaf.mov" - file_icon_name: "play_arrow" - link_name: "Download" - - file_title: "Student Course - Finality Throughflow" - file_info: "Student course." - file_location: "/assets/files/care/AIinHealthcare_throughflow_firstedition.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Card Set - Also available in print" - file_info: "With this card set, you can make students reflect on the ethical aspects of new technologies. What about privacy? Are social contacts not at risk? Which technologies are welcomed? What is undesirable? Are the new technologies affordable for everyone?" - file_location: "/assets/files/care/Cardset_AIinHealthcare_AIOpSchool_Dwengo.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Manual for Card Set" - file_info: "This manual provides additional explanation for the card set." - file_location: "/assets/files/care/AIinHealthcareCardset_InstructionForTeacher.pdf" - file_icon_name: "description" - link_name: "Download" + file_location: '/assets/files/care/Sprouts.mov' + file_icon_name: 'play_arrow' + link_name: 'Download' + - file_title: 'Explanation of Exercises on Graphs from the Student Course' + file_info: 'Which figures represent the same graph? A more formal approach.' + file_location: '/assets/files/care/dezelfdegraafFormeel.mov' + file_icon_name: 'play_arrow' + link_name: 'Download' + - file_title: 'Explanation of Exercises on Graphs from the Student Course' + file_info: 'Which figures represent the same graph? An approach with colors.' + file_location: '/assets/files/care/dezelfdeGraaf.mov' + file_icon_name: 'play_arrow' + link_name: 'Download' + - file_title: 'Student Course - Finality Throughflow' + file_info: 'Student course.' + file_location: '/assets/files/care/AIinHealthcare_throughflow_firstedition.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Card Set - Also available in print' + file_info: 'With this card set, you can make students reflect on the ethical aspects of new technologies. What about privacy? Are social contacts not at risk? Which technologies are welcomed? What is undesirable? Are the new technologies affordable for everyone?' + file_location: '/assets/files/care/Cardset_AIinHealthcare_AIOpSchool_Dwengo.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Manual for Card Set' + file_info: 'This manual provides additional explanation for the card set.' + file_location: '/assets/files/care/AIinHealthcareCardset_InstructionForTeacher.pdf' + file_icon_name: 'description' + link_name: 'Download' - file_title: "Decision Tree 'mBrAIn' Project in Non-compact Form" file_info: "In the research project 'mBrain,' which aims to develop an app predicting a migraine attack, a decision tree was constructed. This decision tree addresses a binary classification problem: there are only two classes, 'Migraine' and 'No Migraine.' (Sources: Femke Ongenae. (2021), UGent; Van Hoecke, S., Ongenae, F., Paemeleire, K., & Vandenbussche, N. (2020). App moet hoofdpijn voorspellen. EOS Wetenschap Special, Technologie en gezondheid, 25.) We have transformed the shape of this decision tree into a binary decision tree to demonstrate that this form is not always user-friendly. For more explanation, see chapter 4 of the student course of this project." - file_location: "/assets/files/care/MBrainBeslissingsboom.png" - file_icon_name: "description" - link_name: "Download" - - file_title: "Search for Speech - Computational Thinking (unplugged activity)" - file_info: "Locked-in syndrome is one of the worst medical conditions. You are completely paralyzed, except that you might still be able to blink with one eye. Your intelligent mind is trapped in a useless body: you can feel everything but cannot communicate. It can happen to anyone, out of nowhere, as a result of a stroke. If you want to help people with the locked-in syndrome, is it best to become a doctor or a nurse? Or can you also help as a computer scientist?" - file_location: "/assets/files/care/ZoektochtNaarSpraak.pdf" - file_icon_name: "description" - link_name: "Download" + file_location: '/assets/files/care/MBrainBeslissingsboom.png' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Search for Speech - Computational Thinking (unplugged activity)' + file_info: 'Locked-in syndrome is one of the worst medical conditions. You are completely paralyzed, except that you might still be able to blink with one eye. Your intelligent mind is trapped in a useless body: you can feel everything but cannot communicate. It can happen to anyone, out of nowhere, as a result of a stroke. If you want to help people with the locked-in syndrome, is it best to become a doctor or a nurse? Or can you also help as a computer scientist?' + file_location: '/assets/files/care/ZoektochtNaarSpraak.pdf' + file_icon_name: 'description' + link_name: 'Download' stem: title: Python in STEM sub_title: Data Visualizations with Python @@ -222,25 +222,25 @@ curricula_page: agriculture: title: AI in Agriculture sub_title: AI in agriculture - description: "Removing rotten tomatoes during harvest? Artificial intelligence can help with that. But how? Students in the second and third grades (SO) get hands-on experience with AI. Perhaps a vibrating conveyor belt can improve the system even more?" + description: 'Removing rotten tomatoes during harvest? Artificial intelligence can help with that. But how? Students in the second and third grades (SO) get hands-on experience with AI. Perhaps a vibrating conveyor belt can improve the system even more?' contact: Questions? Contact us at team@aiopschool.be. The press can contact Francis Wyffels via Francis@dwengo.org. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 curricula_files: - - file_title: "Design" - file_info: "Design of the conveyor belt" - file_location: "/assets/files/art/Transportband_InnoVET_RCH.zip" - file_icon_name: "description" - link_name: "Download" + - file_title: 'Design' + file_info: 'Design of the conveyor belt' + file_location: '/assets/files/art/Transportband_InnoVET_RCH.zip' + file_icon_name: 'description' + link_name: 'Download' art: title: AI in Art sub_title: Drawing Robots in the Classroom - description: "Can we create art with artificial intelligence? Students in the second and third grades (SO) express their creativity with AI and reflect on the result. Is this art? They also discover how AI can protect our cultural heritage." - contact: "" + description: 'Can we create art with artificial intelligence? Students in the second and third grades (SO) express their creativity with AI and reflect on the result. Is this art? They also discover how AI can protect our cultural heritage.' + contact: '' teaser: https://www.youtube.com/embed/dO-E33G20co wegostem: title: WeGoSTEM sub_title: Drawing Robots in the Classroom - description: "We challenge third-grade (BO) children to program a drawing robot. Through play, children learn a lot of STEM skills, from technology to computational thinking." + description: 'We challenge third-grade (BO) children to program a drawing robot. Through play, children learn a lot of STEM skills, from technology to computational thinking.' contact: Questions? Contact us at team@aiopschool.be. The press can contact Francis Wyffels via Francis@dwengo.org. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 @@ -251,61 +251,61 @@ curricula_page: contact: Questions? Contact us at team@aiopschool.be. The press can contact Francis Wyffels via Francis@dwengo.org. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 curricula_files: - - file_title: "Concepts and Approach to Computational Thinking" - file_info: "poster" - file_location: "/assets/files/computational_thinking/CDposterDwengo2.png" - file_icon_name: "description" - link_name: "Download" - - file_title: "Explaining Four Concepts of Computational Thinking" - file_info: "Presentation on four concepts of computational thinking: decomposition, pattern recognition, abstraction, and algorithm. You can download the PDF, open it, present it using CTRL-L, and navigate with the arrow keys." - file_location: "/assets/files/computational_thinking/CD4concepten_33V3gBg.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Concepts and Principles" - file_info: "Overview" - file_location: "/assets/files/computational_thinking/Icoontjes.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged Activity - Emotion Machine (Assignment)" - file_info: "How can you stimulate emotions in a robot?" - file_location: "/assets/files/computational_thinking/emotiemachine_gids.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged Activity - Emotion Machine" - file_info: "How can you stimulate emotions in a robot?" - file_location: "/assets/files/computational_thinking/emotiemachine_gewoon_nl.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged Activity - Color by Number" + - file_title: 'Concepts and Approach to Computational Thinking' + file_info: 'poster' + file_location: '/assets/files/computational_thinking/CDposterDwengo2.png' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Explaining Four Concepts of Computational Thinking' + file_info: 'Presentation on four concepts of computational thinking: decomposition, pattern recognition, abstraction, and algorithm. You can download the PDF, open it, present it using CTRL-L, and navigate with the arrow keys.' + file_location: '/assets/files/computational_thinking/CD4concepten_33V3gBg.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Concepts and Principles' + file_info: 'Overview' + file_location: '/assets/files/computational_thinking/Icoontjes.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged Activity - Emotion Machine (Assignment)' + file_info: 'How can you stimulate emotions in a robot?' + file_location: '/assets/files/computational_thinking/emotiemachine_gids.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged Activity - Emotion Machine' + file_info: 'How can you stimulate emotions in a robot?' + file_location: '/assets/files/computational_thinking/emotiemachine_gewoon_nl.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged Activity - Color by Number' file_info: "Images can be represented in many ways. In this color by number puzzle, you have to reconstruct an image using the given list of numbers; this list tells you which color to fill in each square ('pixel')." - file_location: "/assets/files/computational_thinking/kleurenopnummer1.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged Activity - Human Computer Network" - file_info: "In this activity, students learn how data transfer over the Internet works. Computers, smartphones, and other devices connected via the Internet can communicate with each other. To understand each other, this communication must follow certain agreements. We call these agreements a protocol." - file_location: "/assets/files/computational_thinking/menselijkComputernetwerk.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged Activity - Compression" - file_info: "To send images over networks, we want to represent information with as little data as possible. Compression comes into play here. Using algorithms, images are represented with as few numbers as possible, but in a way that you can still recover the original figure. Other algorithms restore the original image when the information reaches its destination." - file_location: "/assets/files/computational_thinking/puzzel-gecomprimeerdepixel11.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged Activity - Program a Human" + file_location: '/assets/files/computational_thinking/kleurenopnummer1.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged Activity - Human Computer Network' + file_info: 'In this activity, students learn how data transfer over the Internet works. Computers, smartphones, and other devices connected via the Internet can communicate with each other. To understand each other, this communication must follow certain agreements. We call these agreements a protocol.' + file_location: '/assets/files/computational_thinking/menselijkComputernetwerk.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged Activity - Compression' + file_info: 'To send images over networks, we want to represent information with as little data as possible. Compression comes into play here. Using algorithms, images are represented with as few numbers as possible, but in a way that you can still recover the original figure. Other algorithms restore the original image when the information reaches its destination.' + file_location: '/assets/files/computational_thinking/puzzel-gecomprimeerdepixel11.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged Activity - Program a Human' file_info: "Computers cannot interpret, so they literally execute every instruction you give them. The programmer's challenge is to solve problems by breaking them down into small steps that the computer can execute and giving the instructions to the computer correctly." - file_location: "/assets/files/computational_thinking/programmeerEensEenMens.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged Activity - Search for Speech" - file_info: "Locked-in syndrome is one of the worst medical conditions. You are completely paralyzed, except that you may still be able to blink with one eye. Your intelligent mind is trapped in a useless body: you can feel everything but cannot communicate. It can happen to anyone, out of nowhere, as a result of a stroke. If you wanted to help people with locked-in syndrome, would you be better off as a doctor or nurse? Or can you help as a computer scientist?" - file_location: "/assets/files/computational_thinking/ZoektochtNaarSpraak.pdf" - file_icon_name: "description" - link_name: "Download" + file_location: '/assets/files/computational_thinking/programmeerEensEenMens.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged Activity - Search for Speech' + file_info: 'Locked-in syndrome is one of the worst medical conditions. You are completely paralyzed, except that you may still be able to blink with one eye. Your intelligent mind is trapped in a useless body: you can feel everything but cannot communicate. It can happen to anyone, out of nowhere, as a result of a stroke. If you wanted to help people with locked-in syndrome, would you be better off as a doctor or nurse? Or can you help as a computer scientist?' + file_location: '/assets/files/computational_thinking/ZoektochtNaarSpraak.pdf' + file_icon_name: 'description' + link_name: 'Download' math_with_python: title: Python in Math Class sub_title: Python in Mathematics - description: "The programming language Python offers great possibilities to enrich the math class. From the Pythagorean theorem to creating your own graphs, digital image processing, and linear regression, everything becomes clearer with Python." - contact: "" + description: 'The programming language Python offers great possibilities to enrich the math class. From the Pythagorean theorem to creating your own graphs, digital image processing, and linear regression, everything becomes clearer with Python.' + contact: '' teaser: https://www.youtube.com/embed/dO-E33G20co python_programming: title: Programming with Python @@ -316,12 +316,12 @@ curricula_page: physical_computing: title: Physical Computing sub_title: Program Robots in the Classroom - description: "Build a musical instrument, car, or weather station? You can do that with Dwenguino, a microcontroller platform with its own programming environment. Students from both primary and secondary education can get started with it right away. In real life or in our simulator, block-based or textual." + description: 'Build a musical instrument, car, or weather station? You can do that with Dwenguino, a microcontroller platform with its own programming environment. Students from both primary and secondary education can get started with it right away. In real life or in our simulator, block-based or textual.' contact: Questions? Contact us at team@aiopschool.be. The press can contact Francis Wyffels via Francis@dwengo.org. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 curricula_files: - - file_title: "Bouw jouw eigen robot" - file_info: "Build your own driving robot." - file_location: "/assets/files/physical_computing/bouwjouweigenrobot.pdf" - file_icon_name: "link" - link_name: "Download" + - file_title: 'Bouw jouw eigen robot' + file_info: 'Build your own driving robot.' + file_location: '/assets/files/physical_computing/bouwjouweigenrobot.pdf' + file_icon_name: 'link' + link_name: 'Download' diff --git a/backend/_i18n/fr.yml b/backend/_i18n/fr.yml index 577388fc..e3b68924 100644 --- a/backend/_i18n/fr.yml +++ b/backend/_i18n/fr.yml @@ -2,333 +2,333 @@ curricula_page: title: Notre sujets d'enseignement - read_more: "Lees meer" - curricula_files: "Bestanden" + read_more: 'Lees meer' + curricula_files: 'Bestanden' algorithms: title: Algorithmes sub_title: Algorithmes description: "Les élèves de la troisième à la sixième année (enseignement secondaire) apprennent comment utiliser des algorithmes pour résoudre des problèmes. Ils apprennent à concevoir des algorithmes et à analyser l'efficacité de ces derniers. Ils apprennent également à utiliser des algorithmes pour résoudre des problèmes." - contact: "" + contact: '' teaser: https://www.youtube.com/embed/2B6gZ9HdQ1Y basics_ai: title: Basisprincipes van AI sub_title: Basisprincipes van AI - description: "Onder dit lesthema bundelen we verschillende activiteiten waarin de basisprincipes van artificiële intelligentie (AI) aan bod komen. Leerlingen leren wat AI is, hoe het werkt en hoe het kan worden toegepast in verschillende domeinen." - contact: "" + description: 'Onder dit lesthema bundelen we verschillende activiteiten waarin de basisprincipes van artificiële intelligentie (AI) aan bod komen. Leerlingen leren wat AI is, hoe het werkt en hoe het kan worden toegepast in verschillende domeinen.' + contact: '' kiks: - title: "IA et changement climatique" - sub_title: "KIKS" + title: 'IA et changement climatique' + sub_title: 'KIKS' description: "Les élèves de la troisième année du secondaire explorent comment les plantes s'adaptent au changement climatique via leurs stomates. Ils utilisent l'intelligence artificielle et la reconnaissance d'image pour compter ces stomates." - contact: "" - teaser: "https://www.youtube.com/embed/dO-E33G20co" + contact: '' + teaser: 'https://www.youtube.com/embed/dO-E33G20co' curricula_files: - - file_title: "Fiche de projet KIKS" + - file_title: 'Fiche de projet KIKS' file_info: "Il s'agit d'un bref aperçu du projet KIKS avec la structure et les caractéristiques du projet." - file_location: "/assets/files/kiks/projectfiche_kiks.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Le manuel - également disponible en version imprimée" + file_location: '/assets/files/kiks/projectfiche_kiks.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Le manuel - également disponible en version imprimée' file_info: "Nous voulons donner aux enseignants des connaissances de base sur le contenu de ce projet : le changement climatique, la biologie des stomates et la manière dont les plantes s'adaptent à ce changement climatique via les stomates, la recherche scientifique de l'UGent et du Jardin botanique de Meise à l'origine de ce projet, la science citoyenne, ce qu'est l'intelligence artificielle (IA), l'histoire de l'IA, son utilisation et l'éthique qui l'entoure, les principes des images numériques, les mathématiques derrière les algorithmes et les fondements des techniques d'IA actuellement les plus utilisées. Nous expliquons également comment nous avons utilisé KIKS en classe." - file_location: "/assets/files/kiks/KIKS_handleiding_eerstedruk.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Un cours pour les élèves" + file_location: '/assets/files/kiks/KIKS_handleiding_eerstedruk.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Un cours pour les élèves' file_info: "Avec le cours pour les élèves, nous donnons un exemple d'un parcours possible que l'enseignant peut suivre avec les élèves. Le parcours inclut le changement climatique, la biologie des stomates avec une tâche de microscopie, la manière dont les plantes s'adaptent au changement climatique via les stomates, la recherche scientifique de l'UGent et du Jardin botanique de Meise, la collecte de données pour entraîner un réseau neuronal, ce qu'est l'intelligence artificielle (IA), l'histoire de l'IA, son utilisation et l'éthique qui l'entoure, les principes des images numériques, le travail avec les convolutions, les mathématiques derrière l'algorithme du Perceptron, la classification linéaire et non linéaire des données, et les fondements de l'apprentissage machine." - file_location: "/assets/files/kiks/KIKS_leerlingencursus_eerstedruk.pdf" - file_icon_name: "description" - link_name: "Télécharger" + file_location: '/assets/files/kiks/KIKS_leerlingencursus_eerstedruk.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' - file_title: "Les objectifs d'apprentissage" file_info: "Dans le projet KIKS, de nombreux objectifs d'apprentissage peuvent être abordés. L'enseignant décide lui-même des objectifs d'apprentissage liés au projet. De plus, le projet offre de nombreuses possibilités pour permettre aux élèves d'apprendre de manière active et autonome, et pour enseigner les compétences en TIC. KIKS peut également être utilisé pour développer une mission de recherche. Les objectifs d'apprentissage et les plans de cours des différentes institutions contiennent de nombreux objectifs d'apprentissage liés à la biologie, à la géographie et aux mathématiques." - file_location: "/assets/files/kiks/Leerdoelen-KIKS.pdf" - file_icon_name: "description" - link_name: "Télécharger" + file_location: '/assets/files/kiks/Leerdoelen-KIKS.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' - file_title: "La réalisation d'une empreinte de vernis à ongles d'une partie d'une feuille" file_info: "Pour connaître le nombre de stomates sur une partie d'une feuille d'une plante, nous examinons la surface de la feuille sous le microscope. Pour ce faire, nous pouvons retirer une partie de la cuticule très fine de la feuille, mais cela ne fonctionne pas aussi bien pour certaines plantes en raison de la rigidité de la feuille. Cela peut cependant être compensé en utilisant la même méthode que les chercheurs du Jardin botanique de Meise, à savoir prendre une empreinte d'une partie de la surface de la feuille avec du vernis à ongles transparent. L'image microscopique peut être photographiée avec un smartphone." - file_location: "https://vimeo.com/467062270" - file_icon_name: "play_arrow" - link_name: "Voir" + file_location: 'https://vimeo.com/467062270' + file_icon_name: 'play_arrow' + link_name: 'Voir' socialrobot: - title: "Robot social" - sub_title: "Robotique en classe" - description: "Alors que les élèves de la première année du secondaire bricolent et programment un robot social, ils apprennent à résoudre des problèmes complexes grâce à la pensée computationnelle. Ils travaillent de manière ludique sur les nouvelles compétences finales en compétences numériques." - contact: "Questions ? Contactez-nous via team@aiopschool.be. La presse peut contacter Francis Wyffels via Francis@dwengo.org." - teaser: "https://www.youtube.com/embed/tqSnpAKLsu8" + title: 'Robot social' + sub_title: 'Robotique en classe' + description: 'Alors que les élèves de la première année du secondaire bricolent et programment un robot social, ils apprennent à résoudre des problèmes complexes grâce à la pensée computationnelle. Ils travaillent de manière ludique sur les nouvelles compétences finales en compétences numériques.' + contact: 'Questions ? Contactez-nous via team@aiopschool.be. La presse peut contacter Francis Wyffels via Francis@dwengo.org.' + teaser: 'https://www.youtube.com/embed/tqSnpAKLsu8' curricula_files: - - file_title: "Fiche de projet Robot social" + - file_title: 'Fiche de projet Robot social' file_info: "Il s'agit d'un bref aperçu du projet 'Robot social' avec la structure et les caractéristiques du projet." - file_location: "/assets/files/socialrobot/projectfiche_socialerobot.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Collage des robots sociaux" + file_location: '/assets/files/socialrobot/projectfiche_socialerobot.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Collage des robots sociaux' file_info: "Les robots sur cette photo sont des réalisations d'élèves de la première année du secondaire ou des prototypes." - file_location: "/assets/files/socialrobot/collage.png" - file_icon_name: "description" - link_name: "Télécharger" + file_location: '/assets/files/socialrobot/collage.png' + file_icon_name: 'description' + link_name: 'Télécharger' - file_title: "Kit de construction pour le projet 'Robot social'" file_info: "Vous souhaitez que vos élèves conçoivent et construisent également un robot social ? Cela peut se faire avec le kit de construction de Dwengovzw. Sur la figure, vous découvrirez la composition actuelle du kit de construction. Intéressé ? Contactez-nous par e-mail ou trouvez plus d'informations sur cette page du projet." - file_location: "/assets/files/socialrobot/constructiekit_socialerobot.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "De la mission aux compétences finales" + file_location: '/assets/files/socialrobot/constructiekit_socialerobot.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'De la mission aux compétences finales' file_info: "Les compétences finales qui peuvent être travaillées sont liées aux différentes phases du projet 'Robot social'." - file_location: "/assets/files/socialrobot/EindtermenAStroomSsocialeRobot.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Machine à émotions (incomplète) - Pensée computationnelle (activité débranchée)" - file_info: "Activité débranchée" - file_location: "/assets/files/socialrobot/emotiemachine_gewoon_nl.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Machine à émotions (mission) - Pensée computationnelle (activité débranchée)" - file_info: "Activité débranchée" - file_location: "/assets/files/socialrobot/emotiemachine_gids.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Machine à émotions (complète) - Pensée computationnelle (activité débranchée)" - file_info: "Activité débranchée" - file_location: "/assets/files/socialrobot/emotiemachine_ingevuld_nl.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Machine à émotions avec matrice de LED - Pensée computationnelle (activité débranchée)" - file_info: "Activité débranchée" - file_location: "/assets/files/socialrobot/emotiemachine_matrices_nl.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Guide pour les enseignants" + file_location: '/assets/files/socialrobot/EindtermenAStroomSsocialeRobot.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Machine à émotions (incomplète) - Pensée computationnelle (activité débranchée)' + file_info: 'Activité débranchée' + file_location: '/assets/files/socialrobot/emotiemachine_gewoon_nl.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Machine à émotions (mission) - Pensée computationnelle (activité débranchée)' + file_info: 'Activité débranchée' + file_location: '/assets/files/socialrobot/emotiemachine_gids.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Machine à émotions (complète) - Pensée computationnelle (activité débranchée)' + file_info: 'Activité débranchée' + file_location: '/assets/files/socialrobot/emotiemachine_ingevuld_nl.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Machine à émotions avec matrice de LED - Pensée computationnelle (activité débranchée)' + file_info: 'Activité débranchée' + file_location: '/assets/files/socialrobot/emotiemachine_matrices_nl.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Guide pour les enseignants' file_info: "Les fiches regroupées détaillant l'utilisation du Dwenguino et des capteurs et actionneurs." - file_location: "/assets/files/socialrobot/ficheboekje_lkn.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Fiches pour les élèves" + file_location: '/assets/files/socialrobot/ficheboekje_lkn.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Fiches pour les élèves' file_info: "Ces fiches expliquent l'utilisation du Dwenguino et des capteurs et actionneurs." - file_location: "/assets/files/socialrobot/fichesSocialeRobot_lln.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Créer un visage - Pensée computationnelle (activité débranchée)" - file_info: "Activité débranchée" - file_location: "/assets/files/socialrobot/maakeengezicht_activiteit.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Exercices de la MOOC" - file_info: "Aperçu des exercices de programmation dans le MOOC." - file_location: "/assets/files/socialrobot/Opgaven_MOOC.pdf" - file_icon_name: "description" - link_name: "Télécharger" + file_location: '/assets/files/socialrobot/fichesSocialeRobot_lln.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Créer un visage - Pensée computationnelle (activité débranchée)' + file_info: 'Activité débranchée' + file_location: '/assets/files/socialrobot/maakeengezicht_activiteit.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Exercices de la MOOC' + file_info: 'Aperçu des exercices de programmation dans le MOOC.' + file_location: '/assets/files/socialrobot/Opgaven_MOOC.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' - file_title: "Affiche du projet 'Robot social'" file_info: "L'affiche représente les différents aspects du projet." - file_location: "/assets/files/socialrobot/posterSocialeRobot_nl_Qo4ANmV.pdf" - file_icon_name: "description" - link_name: "Télécharger" + file_location: '/assets/files/socialrobot/posterSocialeRobot_nl_Qo4ANmV.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' - file_title: "Guide 'Bonjour robot!'" - file_info: "Avec ce livret, donnez vie à votre propre robot social." - file_location: "/assets/files/socialrobot/handleiding_hallo_robot.pdf" - file_icon_name: "description" - link_name: "Télécharger" + file_info: 'Avec ce livret, donnez vie à votre propre robot social.' + file_location: '/assets/files/socialrobot/handleiding_hallo_robot.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' chatbot: title: "Technologie du langage à l'école" - sub_title: "Se mettre au travail avec un chatbot" - description: "Là où le langage et la technologie se rencontrent, naît le domaine du Traitement du Langage Naturel. Un ordinateur peut-il comprendre, traduire ou même écrire des textes ? Peut-il reconnaître les émotions ? Les élèves de la deuxième et de la troisième année (enseignement secondaire) en apprennent davantage dans ce programme." - contact: "Questions ? Contactez-nous via team@aiopschool.be. La presse peut contacter Francis Wyffels via Francis@dwengo.org." - teaser: "https://www.youtube.com/embed/tqSnpAKLsu8" + sub_title: 'Se mettre au travail avec un chatbot' + description: 'Là où le langage et la technologie se rencontrent, naît le domaine du Traitement du Langage Naturel. Un ordinateur peut-il comprendre, traduire ou même écrire des textes ? Peut-il reconnaître les émotions ? Les élèves de la deuxième et de la troisième année (enseignement secondaire) en apprennent davantage dans ce programme.' + contact: 'Questions ? Contactez-nous via team@aiopschool.be. La presse peut contacter Francis Wyffels via Francis@dwengo.org.' + teaser: 'https://www.youtube.com/embed/tqSnpAKLsu8' curricula_files: - - file_title: "Fiche de projet Chatbot" + - file_title: 'Fiche de projet Chatbot' file_info: "Il s'agit d'un bref aperçu du projet Chatbot avec la structure et les caractéristiques du projet." - file_location: "/assets/files/chatbot/projectfiche_chatbot.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "BrAInfood Chatbots" + file_location: '/assets/files/chatbot/projectfiche_chatbot.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'BrAInfood Chatbots' file_info: "Dans ce BrAInfood destiné aux jeunes, le Centre de connaissances Data & Société donne plus d'informations sur les chatbots. Le BrAInfood contient une histoire fictive sur Lotte qui discute avec un chatbot et transmet potentiellement des informations à des entreprises. En outre, quelques points d'attention concernant les chatbots sont expliqués, ainsi que quelques conseils pour les jeunes afin de mieux protéger leurs données personnelles. De cette manière, nous voulons sensibiliser les jeunes au fonctionnement des chatbots et les encourager à réfléchir aux données qui sont collectées à leur sujet." - file_location: "/assets/files/chatbot/Brainfood13_Chatbots_FR.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "BrAInfood Nouvelles personnalisées" + file_location: '/assets/files/chatbot/Brainfood13_Chatbots_FR.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'BrAInfood Nouvelles personnalisées' file_info: "Dans ce BrAInfood du Centre de connaissances Data & Société, des conseils sont donnés sur la façon de garder le contrôle sur votre fil d'actualité." - file_location: "/assets/files/chatbot/brainfoodrecommendationnews.jpg" - file_icon_name: "description" - link_name: "Télécharger" + file_location: '/assets/files/chatbot/brainfoodrecommendationnews.jpg' + file_icon_name: 'description' + link_name: 'Télécharger' - file_title: "Manuel 'Chatbot' - Également disponible en version imprimée" file_info: "Les enseignants acquièrent, via ce manuel, des informations de base suffisantes pour aborder (une partie du) projet 'Chatbot' en classe. Le livre aborde différents aspects de la technologie du langage, tels que l'histoire de l'intelligence artificielle, ses aspects éthiques, l'analyse des sentiments et la détection du cyberharcèlement, les chatbots, les assistants numériques parlants et la reconnaissance d'auteur. Il aborde également les compétences finales STEM et les compétences finales en compétences numériques et en éducation aux médias." - file_location: "/assets/files/chatbot/Chatbot_handleiding_eerstedruk.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Improbotics - Livret - Version enseignant" - file_info: "Dans la pièce de théâtre Improbotics, un robot social improvise dans les scènes. Le livret contient des informations sur les technologies utilisées." - file_location: "/assets/files/chatbot/Improbotics_lesmap_Enseignant.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Improbotics - Livret - Élèves" - file_info: "Dans la pièce de théâtre Improbotics, un robot social improvise dans les scènes. Le livret contient des informations sur les technologies utilisées." - file_location: "/assets/files/chatbot/Improbotics_lesmap_Eleve.pdf" - file_icon_name: "description" - link_name: "Télécharger" + file_location: '/assets/files/chatbot/Chatbot_handleiding_eerstedruk.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Improbotics - Livret - Version enseignant' + file_info: 'Dans la pièce de théâtre Improbotics, un robot social improvise dans les scènes. Le livret contient des informations sur les technologies utilisées.' + file_location: '/assets/files/chatbot/Improbotics_lesmap_Enseignant.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Improbotics - Livret - Élèves' + file_info: 'Dans la pièce de théâtre Improbotics, un robot social improvise dans les scènes. Le livret contient des informations sur les technologies utilisées.' + file_location: '/assets/files/chatbot/Improbotics_lesmap_Eleve.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' care: - title: "IA dans les soins de santé" + title: 'IA dans les soins de santé' sub_title: "Systèmes d'IA aidant dans les soins de santé" description: "Les hôpitaux utilisent déjà l'intelligence artificielle aujourd'hui. Les élèves de la deuxième et de la troisième année (enseignement secondaire) découvrent quels systèmes existent et comment ils aident les médecins à prendre des décisions. Ainsi, les élèves apprennent les principes de l'arbre de décision, une technique couramment utilisée dans l'apprentissage automatique." - contact: "" - teaser: "https://www.youtube.com/embed/dO-E33G20co" + contact: '' + teaser: 'https://www.youtube.com/embed/dO-E33G20co' curricula_files: - - file_title: "Fiche de projet IA dans les soins de santé" + - file_title: 'Fiche de projet IA dans les soins de santé' file_info: "Il s'agit d'un bref aperçu du projet IA dans les soins de santé avec la structure et les caractéristiques du projet." - file_location: "/assets/files/care/projectfiche_aiindezorg.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Sprouts" + file_location: '/assets/files/care/projectfiche_aiindezorg.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Sprouts' file_info: "Un jeu d'introduction aux 'Graphes'." - file_location: "/assets/files/care/Sprouts.mov" - file_icon_name: "play_arrow" - link_name: "Télécharger" - - file_title: "Explication des exercices de graphes du cours des élèves" - file_info: "Quels dessins représentent le même graphe ? Une approche plus formelle." - file_location: "/assets/files/care/dezelfdegraafFormeel.mov" - file_icon_name: "play_arrow" - link_name: "Télécharger" - - file_title: "Explication des exercices de graphes du cours des élèves" - file_info: "Quels dessins représentent le même graphe ? Une approche avec des couleurs." - file_location: "/assets/files/care/dezelfdeGraaf.mov" - file_icon_name: "play_arrow" - link_name: "Télécharger" - - file_title: "Le cours des élèves - Finalité Générale" - file_info: "Cours des élèves" - file_location: "/assets/files/care/AIindeZorg_doorstroom_eerstedruk.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Ensemble de cartes - Également disponible en version imprimée" + file_location: '/assets/files/care/Sprouts.mov' + file_icon_name: 'play_arrow' + link_name: 'Télécharger' + - file_title: 'Explication des exercices de graphes du cours des élèves' + file_info: 'Quels dessins représentent le même graphe ? Une approche plus formelle.' + file_location: '/assets/files/care/dezelfdegraafFormeel.mov' + file_icon_name: 'play_arrow' + link_name: 'Télécharger' + - file_title: 'Explication des exercices de graphes du cours des élèves' + file_info: 'Quels dessins représentent le même graphe ? Une approche avec des couleurs.' + file_location: '/assets/files/care/dezelfdeGraaf.mov' + file_icon_name: 'play_arrow' + link_name: 'Télécharger' + - file_title: 'Le cours des élèves - Finalité Générale' + file_info: 'Cours des élèves' + file_location: '/assets/files/care/AIindeZorg_doorstroom_eerstedruk.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Ensemble de cartes - Également disponible en version imprimée' file_info: "À l'aide de cet ensemble de cartes, vous pouvez amener les élèves à réfléchir aux aspects éthiques des nouvelles technologies. Qu'en est-il de la vie privée ? Les contacts sociaux ne sont-ils pas compromis ? Quelles technologies sont bien accueillies ? Qu'est-ce qui n'est pas souhaitable ? Les nouvelles technologies sont-elles abordables pour tous ?" - file_location: "/assets/files/care/Kaartset_AIIndeZorg_AIOpSchool_Dwengo.pdf" - file_icon_name: "description" - link_name: "Télécharger" + file_location: '/assets/files/care/Kaartset_AIIndeZorg_AIOpSchool_Dwengo.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' - file_title: "Manuel de l'ensemble de cartes" file_info: "Ce manuel fournit des explications supplémentaires sur l'ensemble de cartes." - file_location: "/assets/files/care/AIIndeZorgKaartenset_UitlegVoorLeerkracht.pdf" - file_icon_name: "description" - link_name: "Télécharger" + file_location: '/assets/files/care/AIIndeZorgKaartenset_UitlegVoorLeerkracht.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' - file_title: "Arbre de décision du projet 'mBrAIn' sous forme non compacte" file_info: "Dans le projet de recherche 'mBrain', qui vise le développement d'une application prédisant une crise de migraine, une arborescence de décision a été construite. Cette arborescence de décision aborde un problème de classification binaire : il n'y a que deux classes, 'Migraine' et 'Pas de migraine'. (Sources : Femke Ongenae. (2021), UGent ; Van Hoecke, S., Ongenae, F., Paemeleire, K., & Vandenbussche, N. (2020). App doit prédire les maux de tête. EOS Wetenschap Special, Technologie en gezondheid, 25.) Nous avons transformé la forme de cette arborescence de décision en une arborescence de décision binaire pour montrer que cette forme n'est pas toujours conviviale. Pour plus d'explications, voir le chapitre 4 du cours des élèves de ce projet." - file_location: "/assets/files/care/MBrainBeslissingsboom.png" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Recherche de la parole - Pensée computationnelle (activité débranchée)" + file_location: '/assets/files/care/MBrainBeslissingsboom.png' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Recherche de la parole - Pensée computationnelle (activité débranchée)' file_info: "Le syndrome d'enfermement est l'une des pires conditions médicales. Vous êtes complètement paralysé, sauf peut-être pour cligner des yeux. Votre esprit intelligent est enfermé dans un corps inutile : vous pouvez tout ressentir, mais pas communiquer. Cela peut arriver à n'importe qui, à tout moment, suite à un AVC. Si vous voulez aider les personnes atteintes du syndrome d'enfermement, vaut-il mieux être médecin ou infirmier ? Ou en tant qu'informaticien, pouvez-vous aussi aider ?" - file_location: "/assets/files/care/ZoektochtNaarSpraak.pdf" - file_icon_name: "description" - link_name: "Télécharger" + file_location: '/assets/files/care/ZoektochtNaarSpraak.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' stem: - title: "Python en STEM" - sub_title: "Visualisations de données avec Python" - description: "Dans ce programme, vous apprendrez à aborder des problèmes complexes de manière plus simple et plus rapide avec le langage de programmation Python. La programmation peut jouer un rôle de liaison entre la science, la technologie, la conception et les mathématiques appliquées. En bref, grâce à Python, nous tirons le meilleur parti de STEM." - contact: "Des questions ? Contactez-nous via team@aiopschool.be. La presse peut contacter Francis Wyffels via Francis@dwengo.org." - teaser: "https://www.youtube.com/embed/tqSnpAKLsu8" + title: 'Python en STEM' + sub_title: 'Visualisations de données avec Python' + description: 'Dans ce programme, vous apprendrez à aborder des problèmes complexes de manière plus simple et plus rapide avec le langage de programmation Python. La programmation peut jouer un rôle de liaison entre la science, la technologie, la conception et les mathématiques appliquées. En bref, grâce à Python, nous tirons le meilleur parti de STEM.' + contact: 'Des questions ? Contactez-nous via team@aiopschool.be. La presse peut contacter Francis Wyffels via Francis@dwengo.org.' + teaser: 'https://www.youtube.com/embed/tqSnpAKLsu8' agriculture: title: "IA dans l'Agriculture" sub_title: "IA dans l'agriculture" description: "Retirer les tomates pourries pendant la récolte ? L'intelligence artificielle peut aider. Mais comment ? Les élèves de la deuxième et de la troisième année (enseignement secondaire) travaillent avec l'IA. Peut-être qu'un tapis roulant vibrant pourrait améliorer le système encore davantage ?" - contact: "Des questions ? Contactez-nous via team@aiopschool.be. La presse peut contacter Francis Wyffels via Francis@dwengo.org." - teaser: "https://www.youtube.com/embed/tqSnpAKLsu8" + contact: 'Des questions ? Contactez-nous via team@aiopschool.be. La presse peut contacter Francis Wyffels via Francis@dwengo.org.' + teaser: 'https://www.youtube.com/embed/tqSnpAKLsu8' curricula_files: - - file_title: "Conception" - file_info: "Conception du tapis roulant" - file_location: "/assets/files/art/Transportband_InnoVET_RCH.zip" - file_icon_name: "description" - link_name: "Télécharger" + - file_title: 'Conception' + file_info: 'Conception du tapis roulant' + file_location: '/assets/files/art/Transportband_InnoVET_RCH.zip' + file_icon_name: 'description' + link_name: 'Télécharger' art: title: "IA dans l'Art" - sub_title: "Robots de dessin en classe" + sub_title: 'Robots de dessin en classe' description: "Peut-on créer de l'art avec l'intelligence artificielle ? Les élèves de la deuxième et de la troisième année (enseignement secondaire) expriment leur créativité avec l'IA et réfléchissent au résultat. Est-ce de l'art ? Ils découvrent également comment l'IA peut protéger notre patrimoine culturel." - contact: "" - teaser: "https://www.youtube.com/embed/dO-E33G20co" + contact: '' + teaser: 'https://www.youtube.com/embed/dO-E33G20co' wegostem: - title: "WeGoSTEM" - sub_title: "Robots de dessin en classe" - description: "Nous mettons au défi les enfants de la troisième année (enseignement primaire) de programmer un robot artistique capable de dessiner. Les enfants apprennent de manière ludique de nombreuses compétences STEM, de la technologie à la pensée informatique." - contact: "Des questions ? Contactez-nous via team@aiopschool.be. La presse peut contacter Francis Wyffels via Francis@dwengo.org." - teaser: "https://www.youtube.com/embed/tqSnpAKLsu8" + title: 'WeGoSTEM' + sub_title: 'Robots de dessin en classe' + description: 'Nous mettons au défi les enfants de la troisième année (enseignement primaire) de programmer un robot artistique capable de dessiner. Les enfants apprennent de manière ludique de nombreuses compétences STEM, de la technologie à la pensée informatique.' + contact: 'Des questions ? Contactez-nous via team@aiopschool.be. La presse peut contacter Francis Wyffels via Francis@dwengo.org.' + teaser: 'https://www.youtube.com/embed/tqSnpAKLsu8' computational_thinking: - title: "Pensée informatique" - sub_title: "Pensée informatique en classe" + title: 'Pensée informatique' + sub_title: 'Pensée informatique en classe' description: "Comment pouvons-nous résoudre des problèmes complexes à l'aide d'un ordinateur ? Grâce à la pensée informatique ! Vous pouvez apprendre cela grâce à diverses activités avec ou sans ordinateur. Nous vous aidons déjà à démarrer." - contact: "Des questions ? Contactez-nous via team@aiopschool.be. La presse peut contacter Francis Wyffels via Francis@dwengo.org." - teaser: "https://www.youtube.com/embed/tqSnpAKLsu8" + contact: 'Des questions ? Contactez-nous via team@aiopschool.be. La presse peut contacter Francis Wyffels via Francis@dwengo.org.' + teaser: 'https://www.youtube.com/embed/tqSnpAKLsu8' curricula_files: - - file_title: "Concepts et approches de la pensée informatique" - file_info: "poster" - file_location: "/assets/files/computational_thinking/CDposterDwengo2.png" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Explication des quatre concepts de la pensée informatique" - file_info: "Présentation des quatre concepts de la pensée informatique : décomposition, reconnaissance de motifs, abstraction et algorithme. Vous pouvez télécharger le PDF > ouvrir > présenter avec CTRL-L et naviguer avec les touches fléchées." - file_location: "/assets/files/computational_thinking/CD4concepten_33V3gBg.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Concepts et principes" - file_info: "Aperçu" - file_location: "/assets/files/computational_thinking/Icoontjes.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Activité sans ordinateur - Machine émotionnelle (tâche)" - file_info: "Comment stimuler les émotions chez un robot ?" - file_location: "/assets/files/computational_thinking/emotiemachine_gids.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Activité sans ordinateur - Machine émotionnelle" - file_info: "Comment stimuler les émotions chez un robot ?" - file_location: "/assets/files/computational_thinking/emotiemachine_gewoon_nl.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Activité sans ordinateur - Coloriage par numéro" + - file_title: 'Concepts et approches de la pensée informatique' + file_info: 'poster' + file_location: '/assets/files/computational_thinking/CDposterDwengo2.png' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Explication des quatre concepts de la pensée informatique' + file_info: 'Présentation des quatre concepts de la pensée informatique : décomposition, reconnaissance de motifs, abstraction et algorithme. Vous pouvez télécharger le PDF > ouvrir > présenter avec CTRL-L et naviguer avec les touches fléchées.' + file_location: '/assets/files/computational_thinking/CD4concepten_33V3gBg.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Concepts et principes' + file_info: 'Aperçu' + file_location: '/assets/files/computational_thinking/Icoontjes.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Activité sans ordinateur - Machine émotionnelle (tâche)' + file_info: 'Comment stimuler les émotions chez un robot ?' + file_location: '/assets/files/computational_thinking/emotiemachine_gids.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Activité sans ordinateur - Machine émotionnelle' + file_info: 'Comment stimuler les émotions chez un robot ?' + file_location: '/assets/files/computational_thinking/emotiemachine_gewoon_nl.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Activité sans ordinateur - Coloriage par numéro' file_info: "Les images peuvent être représentées de nombreuses manières. Dans ce casse-tête de coloriage par numéro, vous devez reconstruire une image en utilisant la liste donnée de numéros ; cette liste vous dit dans quelle couleur remplir chaque carré ('pixel')." - file_location: "/assets/files/computational_thinking/kleurenopnummer1.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Activité sans ordinateur - Un réseau informatique humain" + file_location: '/assets/files/computational_thinking/kleurenopnummer1.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Activité sans ordinateur - Un réseau informatique humain' file_info: "Dans cette activité, les élèves découvrent comment fonctionne le transfert de données sur Internet. Les ordinateurs, les smartphones et d'autres appareils connectés par Internet peuvent communiquer entre eux. Pour se comprendre, cette communication doit suivre certaines règles. Nous appelons ces règles un protocole." - file_location: "/assets/files/computational_thinking/menselijkComputernetwerk.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Activité sans ordinateur - Compression" + file_location: '/assets/files/computational_thinking/menselijkComputernetwerk.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Activité sans ordinateur - Compression' file_info: "Pour envoyer des images sur des réseaux, nous voulons représenter l'information avec le moins de données possible. C'est là qu'intervient la compression. À l'aide d'algorithmes, les images sont représentées avec le moins de nombres possible, mais de manière à ce que vous puissiez récupérer la figure originale. D'autres algorithmes restaurent l'image d'origine une fois que l'information a atteint sa destination." - file_location: "/assets/files/computational_thinking/puzzel-gecomprimeerdepixel11.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Activité sans ordinateur - Programmez un être humain" + file_location: '/assets/files/computational_thinking/puzzel-gecomprimeerdepixel11.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Activité sans ordinateur - Programmez un être humain' file_info: "Les ordinateurs ne peuvent pas interpréter et exécutent donc littéralement chaque instruction que vous leur donnez. Le défi du programmeur consiste à résoudre des problèmes en les divisant en petites étapes exécutables par l'ordinateur, et à donner les instructions à l'ordinateur de la bonne manière." - file_location: "/assets/files/computational_thinking/programmeerEensEenMens.pdf" - file_icon_name: "description" - link_name: "Télécharger" - - file_title: "Activité sans ordinateur - Recherche de la parole" + file_location: '/assets/files/computational_thinking/programmeerEensEenMens.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' + - file_title: 'Activité sans ordinateur - Recherche de la parole' file_info: "Le locked-in syndrome est l'une des pires affections médicales. Vous êtes complètement paralysé, sauf peut-être que vous pouvez cligner des yeux. Votre esprit intelligent est emprisonné dans un corps inutile : vous pouvez tout ressentir, mais pas communiquer. Cela peut arriver à n'importe qui, sans avertissement, à la suite d'une attaque. Si vous voulez aider les personnes atteintes du locked-in syndrome, vaut-il mieux être médecin ou infirmier ? Ou un informaticien peut-il aussi aider ?" - file_location: "/assets/files/computational_thinking/ZoektochtNaarSpraak.pdf" - file_icon_name: "description" - link_name: "Télécharger" + file_location: '/assets/files/computational_thinking/ZoektochtNaarSpraak.pdf' + file_icon_name: 'description' + link_name: 'Télécharger' math_with_python: - title: "Python dans le cours de mathématiques" - sub_title: "Python en mathématiques" + title: 'Python dans le cours de mathématiques' + sub_title: 'Python en mathématiques' description: "Le langage de programmation Python offre des possibilités intéressantes pour enrichir le cours de mathématiques. De la théorie de Pythagore à la création de graphiques personnalisés, en passant par le traitement d'images numériques et la régression linéaire, tout devient plus clair avec Python." - contact: "" - teaser: "https://www.youtube.com/embed/dO-E33G20co" + contact: '' + teaser: 'https://www.youtube.com/embed/dO-E33G20co' python_programming: - title: "Programmation avec Python" - sub_title: "Programmation de base en Python" + title: 'Programmation avec Python' + sub_title: 'Programmation de base en Python' description: "Apprendre les principes de base de la programmation ? C'est possible avec ce programme. Nous utilisons Python et apprenons tout sur les séquences, les structures de répétition et les structures de choix. C'est exactement ce qui est stipulé dans les objectifs finaux. Et plus encore !" - contact: "Des questions ? Contactez-nous via team@aiopschool.be. La presse peut contacter Francis Wyffels via Francis@dwengo.org." - teaser: "https://www.youtube.com/embed/tqSnpAKLsu8" + contact: 'Des questions ? Contactez-nous via team@aiopschool.be. La presse peut contacter Francis Wyffels via Francis@dwengo.org.' + teaser: 'https://www.youtube.com/embed/tqSnpAKLsu8' physical_computing: - title: "Informatique physique" - sub_title: "Programmer des robots en classe" + title: 'Informatique physique' + sub_title: 'Programmer des robots en classe' description: "Construire un instrument de musique, une voiture ou une station météorologique ? C'est possible avec Dwenguino, une plateforme de microcontrôleurs avec son propre environnement de programmation. Les élèves du primaire et du secondaire peuvent commencer à l'utiliser immédiatement. En vrai ou dans notre simulateur, en mode blocs ou textuel." - contact: "Des questions ? Contactez-nous via team@aiopschool.be. La presse peut contacter Francis Wyffels via Francis@dwengo.org." - teaser: "https://www.youtube.com/embed/tqSnpAKLsu8" + contact: 'Des questions ? Contactez-nous via team@aiopschool.be. La presse peut contacter Francis Wyffels via Francis@dwengo.org.' + teaser: 'https://www.youtube.com/embed/tqSnpAKLsu8' curricula_files: - - file_title: "Bouw jouw eigen robot" - file_info: "Construisez votre propre robot de conduite." - file_location: "/assets/files/physical_computing/bouwjouweigenrobot.pdf" - file_icon_name: "link" - link_name: "Download" + - file_title: 'Bouw jouw eigen robot' + file_info: 'Construisez votre propre robot de conduite.' + file_location: '/assets/files/physical_computing/bouwjouweigenrobot.pdf' + file_icon_name: 'link' + link_name: 'Download' diff --git a/backend/_i18n/nl.yml b/backend/_i18n/nl.yml index 98fc0beb..05af16fe 100644 --- a/backend/_i18n/nl.yml +++ b/backend/_i18n/nl.yml @@ -8,357 +8,357 @@ curricula_page: algorithms: title: Algoritmes sub_title: Algoritmes - description: "Leerlingen uit de tweede en de derde graad (SO) leren hoe ze algoritmes kunnen gebruiken om problemen op te lossen. Ze leren hoe ze algoritmes kunnen ontwerpen en hoe ze de efficiëntie van algoritmes kunnen analyseren. Ze leren ook hoe ze algoritmes kunnen gebruiken om problemen op te lossen." - contact: "" + description: 'Leerlingen uit de tweede en de derde graad (SO) leren hoe ze algoritmes kunnen gebruiken om problemen op te lossen. Ze leren hoe ze algoritmes kunnen ontwerpen en hoe ze de efficiëntie van algoritmes kunnen analyseren. Ze leren ook hoe ze algoritmes kunnen gebruiken om problemen op te lossen.' + contact: '' basics_ai: title: Basisprincipes van AI sub_title: Basisprincipes van AI - description: "Onder dit lesthema bundelen we verschillende activiteiten waarin de basisprincipes van artificiële intelligentie (AI) aan bod komen. Leerlingen leren wat AI is, hoe het werkt en hoe het kan worden toegepast in verschillende domeinen." - contact: "" + description: 'Onder dit lesthema bundelen we verschillende activiteiten waarin de basisprincipes van artificiële intelligentie (AI) aan bod komen. Leerlingen leren wat AI is, hoe het werkt en hoe het kan worden toegepast in verschillende domeinen.' + contact: '' kiks: title: AI en Klimaat sub_title: KIKS - description: "Leerlingen uit de derde graad (SO) onderzoeken hoe planten zich via hun huidmondjes aanpassen aan de klimaatverandering. Daarvoor tellen ze deze huidmondjes met artificiële intelligentie en beeldherkenning." - contact: "" + description: 'Leerlingen uit de derde graad (SO) onderzoeken hoe planten zich via hun huidmondjes aanpassen aan de klimaatverandering. Daarvoor tellen ze deze huidmondjes met artificiële intelligentie en beeldherkenning.' + contact: '' teaser: https://www.youtube.com/embed/dO-E33G20co curricula_files: - - file_title: "Projectfiche KIKS" - file_info: "Dit is een kort overzicht van het KIKS-project met projectstructuur- en kenmerken." - file_location: "/assets/files/kiks/projectfiche_kiks.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "De handleiding - ook verkrijgbaar in gedrukte versie" - file_info: "We willen de leerkrachten achtergrondkennis geven over de inhoud van dit project: de klimaatverandering, de biologie van de huidmondjes en de manier waarop planten zich via de huidmondjes aan die klimaatverandering aanpassen, het wetenschappelijk onderzoek van de UGent en de Plantentuin Meise dat aan de grondslag ligt van dit project, burgerwetenschap, wat is artificiële intelligentie (AI), de geschiedenis van AI, het gebruik ervan en de ethiek errond, de principes van digitale beelden, de wiskunde achter de algoritmen en de fundamenten van de momenteel meest gebruikte AI-technieken. We geven ook aan hoe wij met KIKS aan de slag gegaan zijn in de klas.​" - file_location: "/assets/files/kiks/KIKS_handleiding_eerstedruk.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Een leerlingencursus" - file_info: "Met de leerlingencursus geven we een voorbeeld van een mogelijk, uitgebreid traject dat een leerkracht met leerlingen kan doorlopen. Het traject omvat de klimaatverandering, de biologie van de huidmondjes met een microscopie-opdracht, de manier waarop planten zich via de huidmondjes aan die klimaatverandering aanpassen, het wetenschappelijk onderzoek van de UGent en de Plantentuin Meise, het verzamelen van de data om een neuraal netwerk te trainen, wat is artificiële intelligentie (AI), de geschiedenis van AI, het gebruik ervan en de ethiek errond, de principes van digitale beelden, het werken met convoluties, de wiskunde achter het Perceptron-algoritme, het lineaire en niet-lineaire classificeren van data, en de fundamenten van machinaal leren." - file_location: "/assets/files/kiks/KIKS_leerlingencursus_eerstedruk.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "De leerplandoelen" + - file_title: 'Projectfiche KIKS' + file_info: 'Dit is een kort overzicht van het KIKS-project met projectstructuur- en kenmerken.' + file_location: '/assets/files/kiks/projectfiche_kiks.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'De handleiding - ook verkrijgbaar in gedrukte versie' + file_info: 'We willen de leerkrachten achtergrondkennis geven over de inhoud van dit project: de klimaatverandering, de biologie van de huidmondjes en de manier waarop planten zich via de huidmondjes aan die klimaatverandering aanpassen, het wetenschappelijk onderzoek van de UGent en de Plantentuin Meise dat aan de grondslag ligt van dit project, burgerwetenschap, wat is artificiële intelligentie (AI), de geschiedenis van AI, het gebruik ervan en de ethiek errond, de principes van digitale beelden, de wiskunde achter de algoritmen en de fundamenten van de momenteel meest gebruikte AI-technieken. We geven ook aan hoe wij met KIKS aan de slag gegaan zijn in de klas.​' + file_location: '/assets/files/kiks/KIKS_handleiding_eerstedruk.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Een leerlingencursus' + file_info: 'Met de leerlingencursus geven we een voorbeeld van een mogelijk, uitgebreid traject dat een leerkracht met leerlingen kan doorlopen. Het traject omvat de klimaatverandering, de biologie van de huidmondjes met een microscopie-opdracht, de manier waarop planten zich via de huidmondjes aan die klimaatverandering aanpassen, het wetenschappelijk onderzoek van de UGent en de Plantentuin Meise, het verzamelen van de data om een neuraal netwerk te trainen, wat is artificiële intelligentie (AI), de geschiedenis van AI, het gebruik ervan en de ethiek errond, de principes van digitale beelden, het werken met convoluties, de wiskunde achter het Perceptron-algoritme, het lineaire en niet-lineaire classificeren van data, en de fundamenten van machinaal leren.' + file_location: '/assets/files/kiks/KIKS_leerlingencursus_eerstedruk.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'De leerplandoelen' file_info: "Binnen het KIKS-project kunnen behoorlijk veel leerdoelen aan bod komen. De leerkracht bepaalt zelf welke leerdoelen in verband gebracht worden met het project. Bovendien biedt het project heel wat mogelijkheden om de leerlingen actief en zelfstandig te laten leren en om ICT-vaardigheden bij te brengen. KIKS kan ook gebruikt worden om een onderzoeksopdracht uit te werken.\n In de minimumdoelen en leerplannen van de verschillende koepels zijn heel wat leerdoelen te vinden die KIKS linken met biologie, aardrijkskunde en wiskunde." - file_location: "/assets/files/kiks/Leerdoelen-KIKS.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Het maken van een nagellakafdruk van een deel van een blad" + file_location: '/assets/files/kiks/Leerdoelen-KIKS.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Het maken van een nagellakafdruk van een deel van een blad' file_info: "Om het aantal huidmondjes op een deel van een blad van een plant te kennen, bekijken we het bladoppervlak onder de microscoop. We kunnen daarvoor een stuk van de flinterdunne cuticula van het blad verwijderen, maar bij sommige planten lukt dat niet zo goed, bijvoorbeeld door de stugheid van het blad.\nDit kan echter opgevangen worden door dezelfde methode te gebruiken als de onderzoekers van de Plantentuin Meise, nl. een afdruk nemen van een deel van het bladoppervlak met doorzichtige nagellak.\nHet miscroscopische beeld kan met een smartphone gefotografeerd worden." - file_location: "https://www.youtube.com/watch?v=JptF3jhOV5k" - file_icon_name: "play_arrow" - link_name: "Kijk" + file_location: 'https://www.youtube.com/watch?v=JptF3jhOV5k' + file_icon_name: 'play_arrow' + link_name: 'Kijk' socialrobot: title: Sociale robot sub_title: Robotica in de klas - description: "Terwijl leerlingen uit de eerste graad (SO) een sociale robot knutselen en programmeren, leren ze complexe problemen oplossen via computationeel denken. Spelenderwijs werken ze aan de nieuwe eindtermen rond digitale competenties." + description: 'Terwijl leerlingen uit de eerste graad (SO) een sociale robot knutselen en programmeren, leren ze complexe problemen oplossen via computationeel denken. Spelenderwijs werken ze aan de nieuwe eindtermen rond digitale competenties.' contact: Vragen? Contacteer ons via team@aiopschool.be. De pers kan contact opnemen met Francis wyffels via Francis@dwengo.org. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 curricula_files: - - file_title: "Projectfiche Sociale Robot" + - file_title: 'Projectfiche Sociale Robot' file_info: "Dit is een kort overzicht van het 'Sociale Robot'-project met projectstructuur en -kenmerken." - file_location: "/assets/files/socialrobot/projectfiche_socialerobot.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Collage sociale robots" - file_info: "De robots op deze foto zijn realisaties van leerlingen van de eerste graad van het secundair onderwijs of zijn prototypes.​" - file_location: "/assets/files/socialrobot/collage.png" - file_icon_name: "description" - link_name: "Download" + file_location: '/assets/files/socialrobot/projectfiche_socialerobot.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Collage sociale robots' + file_info: 'De robots op deze foto zijn realisaties van leerlingen van de eerste graad van het secundair onderwijs of zijn prototypes.​' + file_location: '/assets/files/socialrobot/collage.png' + file_icon_name: 'description' + link_name: 'Download' - file_title: "Constructiekit voor 'Sociale Robot'-project" - file_info: "​Wil jij dat jouw leerlingen ook een sociale robot ontwerpen en bouwen? Dat kan via de constructiekit van Dwengo vzw. Op de figuur ontdek je de huidige samenstelling van de constructiekit. Geïnteresseerd? Contacteer ons via e-mail, bekijk de kit in de shop, of vind meer informatie op deze projectpagina." - file_location: "/assets/files/socialrobot/constructiekit_socialerobot.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Van project naar minimumdoelen eerste graad A-stroom" + file_info: '​Wil jij dat jouw leerlingen ook een sociale robot ontwerpen en bouwen? Dat kan via de constructiekit van Dwengo vzw. Op de figuur ontdek je de huidige samenstelling van de constructiekit. Geïnteresseerd? Contacteer ons via e-mail, bekijk de kit in de shop, of vind meer informatie op deze projectpagina.' + file_location: '/assets/files/socialrobot/constructiekit_socialerobot.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Van project naar minimumdoelen eerste graad A-stroom' file_info: "De minimumdoelen waaraan gewerkt kan worden, worden gelinkt aan de verschillende fasen van het 'Sociale Robot'-project.​" - file_location: "/assets/files/socialrobot/MinimumdoelenA-stroomSocialeRobot.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Van project naar minimumdoelen eerste graad B-stroom" + file_location: '/assets/files/socialrobot/MinimumdoelenA-stroomSocialeRobot.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Van project naar minimumdoelen eerste graad B-stroom' file_info: "De minimumdoelen waaraan gewerkt kan worden, worden gelinkt aan de verschillende fasen van het 'Sociale Robot'-project.​" - file_location: "/assets/files/socialrobot/minimumdoelenBstroomsocialerobot.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Van project naar minimumdoelen tweede graad" + file_location: '/assets/files/socialrobot/minimumdoelenBstroomsocialerobot.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Van project naar minimumdoelen tweede graad' file_info: "De minimumdoelen waaraan gewerkt kan worden, worden gelinkt aan de verschillende fasen van het 'Sociale Robot'-project.​" - file_location: "/assets/files/socialrobot/minimumdoelentweedegraadsocialerobot.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Emotiemachine (onvolledig) - Computationeel denken (unplugged activiteit)" - file_info: "​Unplugged activiteit" - file_location: "/assets/files/socialrobot/emotiemachine_gewoon_nl.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Emotiemachine (opdracht) - Computationeel denken (unplugged activiteit)" - file_info: "Unplugged activiteit​" - file_location: "/assets/files/socialrobot/emotiemachine_gids.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Emotiemachine (volledig) - Computationeel denken (unplugged activiteit)" - file_info: "Unplugged activiteit​" - file_location: "/assets/files/socialrobot/emotiemachine_ingevuld_nl.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Emotiemachine met ledmatrix - Computationeel denken (unplugged activiteit)" - file_info: "Unplugged activiteit​" - file_location: "/assets/files/socialrobot/emotiemachine_matrices_nl.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Ficheboekje voor leerkrachten" - file_info: "De gebundelde fiches waarin het gebruik van de Dwenguino en van de sensoren en actuatoren uit de doeken wordt gedaan." - file_location: "/assets/files/socialrobot/ficheboekje_lkr.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Fiches voor de leerlingen" - file_info: "In deze fiches wordt het gebruik van de Dwenguino en van de sensoren en actuatoren uit de doeken gedaan.​" - file_location: "/assets/files/socialrobot/fiches_lln.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Maak een gezicht - Computationeel denken (unplugged activiteit)" - file_info: "Unplugged activiteit​" - file_location: "/assets/files/socialrobot/maakeengezicht_activiteit.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Opgaven van opdrachten in de MOOC" - file_info: "​Een overzicht van de programmeeroefeningen in de MOOC" - file_location: "/assets/files/socialrobot/Opgaven_MOOC.pdf" - file_icon_name: "description" - link_name: "Download" + file_location: '/assets/files/socialrobot/minimumdoelentweedegraadsocialerobot.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Emotiemachine (onvolledig) - Computationeel denken (unplugged activiteit)' + file_info: '​Unplugged activiteit' + file_location: '/assets/files/socialrobot/emotiemachine_gewoon_nl.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Emotiemachine (opdracht) - Computationeel denken (unplugged activiteit)' + file_info: 'Unplugged activiteit​' + file_location: '/assets/files/socialrobot/emotiemachine_gids.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Emotiemachine (volledig) - Computationeel denken (unplugged activiteit)' + file_info: 'Unplugged activiteit​' + file_location: '/assets/files/socialrobot/emotiemachine_ingevuld_nl.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Emotiemachine met ledmatrix - Computationeel denken (unplugged activiteit)' + file_info: 'Unplugged activiteit​' + file_location: '/assets/files/socialrobot/emotiemachine_matrices_nl.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Ficheboekje voor leerkrachten' + file_info: 'De gebundelde fiches waarin het gebruik van de Dwenguino en van de sensoren en actuatoren uit de doeken wordt gedaan.' + file_location: '/assets/files/socialrobot/ficheboekje_lkr.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Fiches voor de leerlingen' + file_info: 'In deze fiches wordt het gebruik van de Dwenguino en van de sensoren en actuatoren uit de doeken gedaan.​' + file_location: '/assets/files/socialrobot/fiches_lln.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Maak een gezicht - Computationeel denken (unplugged activiteit)' + file_info: 'Unplugged activiteit​' + file_location: '/assets/files/socialrobot/maakeengezicht_activiteit.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Opgaven van opdrachten in de MOOC' + file_info: '​Een overzicht van de programmeeroefeningen in de MOOC' + file_location: '/assets/files/socialrobot/Opgaven_MOOC.pdf' + file_icon_name: 'description' + link_name: 'Download' - file_title: "Poster 'Sociale Robot'-project" - file_info: "De poster geeft de verschillende aspecten van het project weer.​" - file_location: "/assets/files/socialrobot/posterSocialeRobot_nl_Qo4ANmV.pdf" - file_icon_name: "description" - link_name: "Download" + file_info: 'De poster geeft de verschillende aspecten van het project weer.​' + file_location: '/assets/files/socialrobot/posterSocialeRobot_nl_Qo4ANmV.pdf' + file_icon_name: 'description' + link_name: 'Download' - file_title: "Handleiding 'Hallo robot!'" - file_info: "Met dit lesboekje breng je je eigen sociale robot tot leven.​" - file_location: "/assets/files/socialrobot/handleiding_hallo_robot.pdf" - file_icon_name: "description" - link_name: "Download" + file_info: 'Met dit lesboekje breng je je eigen sociale robot tot leven.​' + file_location: '/assets/files/socialrobot/handleiding_hallo_robot.pdf' + file_icon_name: 'description' + link_name: 'Download' agriculture: title: AI in de Landbouw sub_title: AI in de landbouw - description: "Rotte tomaten weghalen tijdens de oogst? Daar kan artificiële intelligentie bij helpen. Maar hoe? Leerlingen uit de tweede en derde graad (SO) gaan met AI aan de slag. Misschien kan een trillende lopende band het systeem nog beter maken?" + description: 'Rotte tomaten weghalen tijdens de oogst? Daar kan artificiële intelligentie bij helpen. Maar hoe? Leerlingen uit de tweede en derde graad (SO) gaan met AI aan de slag. Misschien kan een trillende lopende band het systeem nog beter maken?' contact: Vragen? Contacteer ons via team@aiopschool.be. De pers kan contact opnemen met Francis wyffels via Francis@dwengo.org. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 curricula_files: - - file_title: "Ontwerp" - file_info: "Ontwerp van de lopende band" - file_location: "/assets/files/art/Transportband_InnoVET_RCH.zip" - file_icon_name: "description" - link_name: "Download" - - file_title: "De lopende band" - file_info: "Video van de detectie van tomaten" - file_location: "https://www.youtube.com/watch?v=6TSqY4ECMU04" - file_icon_name: "play_arrow" - link_name: "Kijk" + - file_title: 'Ontwerp' + file_info: 'Ontwerp van de lopende band' + file_location: '/assets/files/art/Transportband_InnoVET_RCH.zip' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'De lopende band' + file_info: 'Video van de detectie van tomaten' + file_location: 'https://www.youtube.com/watch?v=6TSqY4ECMU04' + file_icon_name: 'play_arrow' + link_name: 'Kijk' art: title: AI in de Kunst sub_title: Tekenrobots in de klas - description: "Kunnen we kunst maken met artificiële intelligentie? Leerlingen uit de tweede en derde graad (SO) leven zich creatief uit met AI en reflecteren over het resultaat. Is dit kunst? Ook ontdekken ze hoe AI ons cultureel erfgoed kan beschermen." - contact: "" + description: 'Kunnen we kunst maken met artificiële intelligentie? Leerlingen uit de tweede en derde graad (SO) leven zich creatief uit met AI en reflecteren over het resultaat. Is dit kunst? Ook ontdekken ze hoe AI ons cultureel erfgoed kan beschermen.' + contact: '' teaser: https://www.youtube.com/embed/dO-E33G20co wegostem: title: WeGoSTEM sub_title: Tekenrobots in de klas - description: "We dagen kinderen van de derde graad (BO) uit om een kunstrobot die kan tekenen te programmeren. Spelenderwijs leren de kinderen heel wat STEM-vaardigheden, van techniek tot computationeel denken." + description: 'We dagen kinderen van de derde graad (BO) uit om een kunstrobot die kan tekenen te programmeren. Spelenderwijs leren de kinderen heel wat STEM-vaardigheden, van techniek tot computationeel denken.' contact: Vragen? Contacteer ons via team@aiopschool.be. De pers kan contact opnemen met Francis wyffels via Francis@dwengo.org. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 computational_thinking: title: Computationeel denken sub_title: Computationeel denken in de klas - description: "Hoe kunnen we complexe problemen oplossen met behulp van een computer? Dankzij computationeel denken! Dat kan je leren via allerlei activiteiten met óf zonder computer. Wij helpen je alvast op weg." + description: 'Hoe kunnen we complexe problemen oplossen met behulp van een computer? Dankzij computationeel denken! Dat kan je leren via allerlei activiteiten met óf zonder computer. Wij helpen je alvast op weg.' contact: Vragen? Contacteer ons via team@aiopschool.be. De pers kan contact opnemen met Francis wyffels via Francis@dwengo.org. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 curricula_files: - - file_title: "Computationeel denken en programmeren in een STEM context" - file_info: "Informatievideo over het project" - file_location: "https://www.youtube.com/watch?v=Nifa0vooyKg" - file_icon_name: "play_arrow" - link_name: "Kijk" - - file_title: "Concepten en aanpak computationeel denken" - file_info: "Poster​" - file_location: "/assets/files/computational_thinking/CDposterDwengo2.png" - file_icon_name: "description" - link_name: "Download" - - file_title: "Vier concepten van Computationeel denken uitgelegd" - file_info: "Presentatie over vier concepten van computationeel denken: decompositie, patroonherkenning, abstractie en algoritme. Je kan de pdf downloaden > openen > presenteren via CTRL-L en navigeren met de pijltjestoetsen." - file_location: "/assets/files/computational_thinking/CD4concepten_33V3gBg.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Concepten en principes" - file_info: "Overzicht​" - file_location: "/assets/files/computational_thinking/Icoontjes.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged activiteit - Emotiemachine (opdracht)" - file_info: "Hoe kan je emoties stimuleren bij een robot?​" - file_location: "/assets/files/computational_thinking/emotiemachine_gids.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged activiteit - Emotiemachine" - file_info: "Hoe kan je emoties stimuleren bij een robot?​" - file_location: "/assets/files/computational_thinking/emotiemachine_gewoon_nl.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged activiteit - Kleuren op nummer" - file_info: "​Afbeeldingen kunnen op veel manieren worden gerepresenteerd. In deze kleuren op nummer puzzel moet je een afbeelding reconstrueren, gebruikmakend van de gegeven lijst van nummers; deze lijst vertelt je in welke kleur je elk vierkant (‘pixel’) inkleurt." - file_location: "/assets/files/computational_thinking/kleurenopnummer1.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged activiteit - Een menselijk computernetwerk" - file_info: "In deze activiteit maken de leerlingen kennis met hoe overdracht van gegevens over het internet werkt. Computers, smartphones en andere toestellen die met elkaar verbonden zijn via het internet, kunnen met elkaar communiceren. Om elkaar te kunnen begrijpen, dient die communicatie volgens bepaalde afspraken te verlopen. We noemen deze afspraken een protocol.​" - file_location: "/assets/files/computational_thinking/menselijkComputernetwerk.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged activiteit - Comprimeren" - file_info: "Om afbeeldingen te verzenden over netwerken, willen we de informatie met zo weinig mogelijk data representeren. Daar komt compressie aan te pas. Met behulp van algoritmes worden afbeeldingen met zo weinig mogelijk getallen gerepresenteerd, maar wel op zo’n manier dat je de oorspronkelijke figuur nog kunt terugkrijgen. Andere algoritmes herstellen de oorspronkelijke afbeelding als de informatie de bestemming bereikt heeft.​" - file_location: "/assets/files/computational_thinking/puzzel-gecomprimeerdepixel11.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged activiteit - Programmeer eens een mens" - file_info: "Computers kunnen niet interpreteren en voeren dus letterlijk iedere instructie uit die je ze geeft. De uitdaging van de programmeur bestaat erin problemen op te lossen door ze op te delen in kleine stappen die uitvoerbaar zijn door de computer, en de instructies op de juiste manier aan de computer te geven.​" - file_location: "/assets/files/computational_thinking/programmeerEensEenMens.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Unplugged activiteit - Zoektocht naar spraak" - file_info: "Het locked-in syndroom is een van de ergste medische aandoeningen. Je bent volledig verlamd, behalve dat je misschien nog kunt knipperen met een oog. Je intelligente geest zit opgesloten in een nutteloos lichaam: je kan alles voelen, maar niet communiceren. Het kan iedereen overkomen, uit het niets, als gevolg van een beroerte. Als je mensen met het locked-in syndroom zou willen helpen, word je dan best arts of verpleegkundige? Of kan je als computerwetenschapper ook helpen?​" - file_location: "/assets/files/computational_thinking/ZoektochtNaarSpraak.pdf" - file_icon_name: "description" - link_name: "Download" + - file_title: 'Computationeel denken en programmeren in een STEM context' + file_info: 'Informatievideo over het project' + file_location: 'https://www.youtube.com/watch?v=Nifa0vooyKg' + file_icon_name: 'play_arrow' + link_name: 'Kijk' + - file_title: 'Concepten en aanpak computationeel denken' + file_info: 'Poster​' + file_location: '/assets/files/computational_thinking/CDposterDwengo2.png' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Vier concepten van Computationeel denken uitgelegd' + file_info: 'Presentatie over vier concepten van computationeel denken: decompositie, patroonherkenning, abstractie en algoritme. Je kan de pdf downloaden > openen > presenteren via CTRL-L en navigeren met de pijltjestoetsen.' + file_location: '/assets/files/computational_thinking/CD4concepten_33V3gBg.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Concepten en principes' + file_info: 'Overzicht​' + file_location: '/assets/files/computational_thinking/Icoontjes.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged activiteit - Emotiemachine (opdracht)' + file_info: 'Hoe kan je emoties stimuleren bij een robot?​' + file_location: '/assets/files/computational_thinking/emotiemachine_gids.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged activiteit - Emotiemachine' + file_info: 'Hoe kan je emoties stimuleren bij een robot?​' + file_location: '/assets/files/computational_thinking/emotiemachine_gewoon_nl.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged activiteit - Kleuren op nummer' + file_info: '​Afbeeldingen kunnen op veel manieren worden gerepresenteerd. In deze kleuren op nummer puzzel moet je een afbeelding reconstrueren, gebruikmakend van de gegeven lijst van nummers; deze lijst vertelt je in welke kleur je elk vierkant (‘pixel’) inkleurt.' + file_location: '/assets/files/computational_thinking/kleurenopnummer1.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged activiteit - Een menselijk computernetwerk' + file_info: 'In deze activiteit maken de leerlingen kennis met hoe overdracht van gegevens over het internet werkt. Computers, smartphones en andere toestellen die met elkaar verbonden zijn via het internet, kunnen met elkaar communiceren. Om elkaar te kunnen begrijpen, dient die communicatie volgens bepaalde afspraken te verlopen. We noemen deze afspraken een protocol.​' + file_location: '/assets/files/computational_thinking/menselijkComputernetwerk.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged activiteit - Comprimeren' + file_info: 'Om afbeeldingen te verzenden over netwerken, willen we de informatie met zo weinig mogelijk data representeren. Daar komt compressie aan te pas. Met behulp van algoritmes worden afbeeldingen met zo weinig mogelijk getallen gerepresenteerd, maar wel op zo’n manier dat je de oorspronkelijke figuur nog kunt terugkrijgen. Andere algoritmes herstellen de oorspronkelijke afbeelding als de informatie de bestemming bereikt heeft.​' + file_location: '/assets/files/computational_thinking/puzzel-gecomprimeerdepixel11.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged activiteit - Programmeer eens een mens' + file_info: 'Computers kunnen niet interpreteren en voeren dus letterlijk iedere instructie uit die je ze geeft. De uitdaging van de programmeur bestaat erin problemen op te lossen door ze op te delen in kleine stappen die uitvoerbaar zijn door de computer, en de instructies op de juiste manier aan de computer te geven.​' + file_location: '/assets/files/computational_thinking/programmeerEensEenMens.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Unplugged activiteit - Zoektocht naar spraak' + file_info: 'Het locked-in syndroom is een van de ergste medische aandoeningen. Je bent volledig verlamd, behalve dat je misschien nog kunt knipperen met een oog. Je intelligente geest zit opgesloten in een nutteloos lichaam: je kan alles voelen, maar niet communiceren. Het kan iedereen overkomen, uit het niets, als gevolg van een beroerte. Als je mensen met het locked-in syndroom zou willen helpen, word je dan best arts of verpleegkundige? Of kan je als computerwetenschapper ook helpen?​' + file_location: '/assets/files/computational_thinking/ZoektochtNaarSpraak.pdf' + file_icon_name: 'description' + link_name: 'Download' math_with_python: title: Python in de Wiskundeles sub_title: Python in wiskunde - description: "De programmeertaal Python biedt toffe mogelijkheden om de wiskundeles te verrijken. Van de stelling van Pythagoras tot de opmaak van eigen grafieken, digitale beeldverwerking en lineaire regressie, alles wordt duidelijker met Python." - contact: "" + description: 'De programmeertaal Python biedt toffe mogelijkheden om de wiskundeles te verrijken. Van de stelling van Pythagoras tot de opmaak van eigen grafieken, digitale beeldverwerking en lineaire regressie, alles wordt duidelijker met Python.' + contact: '' teaser: https://www.youtube.com/embed/dO-E33G20co python_programming: title: Programmeren met Python sub_title: Basis programmeren in Python - description: "De basisprincipes van programmeren aanleren? Dat kan perfect via dit pakket. We gaan aan de slag met Python en leren alles over sequenties, herhalingsstructuur en keuzestructuur. Dat is precies wat er in de eindtermen staat. En meer!" + description: 'De basisprincipes van programmeren aanleren? Dat kan perfect via dit pakket. We gaan aan de slag met Python en leren alles over sequenties, herhalingsstructuur en keuzestructuur. Dat is precies wat er in de eindtermen staat. En meer!' contact: Vragen? Contacteer ons via team@aiopschool.be. De pers kan contact opnemen met Francis wyffels via Francis@dwengo.org. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 stem: title: Python in STEM sub_title: Datavisualisaties met Python - description: "In dit pakket leer je complexe problemen eenvoudiger én sneller aanpakken met de programmeertaal Python. Programmeren kan immers een verbindende rol spelen tussen wetenschap, techniek, ontwerp en toegepaste wiskunde. Kortom, dankzij Python halen we het beste uit STEM." + description: 'In dit pakket leer je complexe problemen eenvoudiger én sneller aanpakken met de programmeertaal Python. Programmeren kan immers een verbindende rol spelen tussen wetenschap, techniek, ontwerp en toegepaste wiskunde. Kortom, dankzij Python halen we het beste uit STEM.' contact: Vragen? Contacteer ons via team@aiopschool.be. De pers kan contact opnemen met Francis wyffels via Francis@dwengo.org. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 care: title: AI in de Zorg sub_title: AI systemen die helpen in de zorg - description: "Ziekenhuizen maken vandaag al gebruik van artificiële intelligentie. Leerlingen uit de tweede en derde graad (SO) ontdekken welke systemen er bestaan en hoe ze dokters helpen om beslissingen te nemen. Zo leren leerlingen de principes van de beslissingsboom, een veelgebruikte techniek in machine learning." - contact: "" + description: 'Ziekenhuizen maken vandaag al gebruik van artificiële intelligentie. Leerlingen uit de tweede en derde graad (SO) ontdekken welke systemen er bestaan en hoe ze dokters helpen om beslissingen te nemen. Zo leren leerlingen de principes van de beslissingsboom, een veelgebruikte techniek in machine learning.' + contact: '' teaser: https://www.youtube.com/embed/dO-E33G20co curricula_files: - - file_title: "Projectfiche AI in de Zorg" - file_info: "Dit is een kort overzicht van project AI in de Zorg met projectstructuur- en kenmerken." - file_location: "/assets/files/care/projectfiche_aiindezorg.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Sprouts" + - file_title: 'Projectfiche AI in de Zorg' + file_info: 'Dit is een kort overzicht van project AI in de Zorg met projectstructuur- en kenmerken.' + file_location: '/assets/files/care/projectfiche_aiindezorg.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Sprouts' file_info: "Een spel ter inleiding op 'Grafen'.​" - file_location: "/assets/files/care/Sprouts.mov" - file_icon_name: "play_arrow" - link_name: "Download" - - file_title: "Uitleg bij oefeningen grafen uit de leerlingencursus" - file_info: "Welke figuren stellen er dezelfde graaf voor? Een meer formele werkwijze.​" - file_location: "/assets/files/care/dezelfdegraafFormeel.mov" - file_icon_name: "play_arrow" - link_name: "Download" - - file_title: "Uitleg bij oefeningen grafen uit de leerlingencursus" - file_info: "Welke figuren stellen er dezelfde graaf voor? Een werkwijze met kleuren.​" - file_location: "/assets/files/care/dezelfdeGraaf.mov" - file_icon_name: "play_arrow" - link_name: "Download" - - file_title: "De leerlingencursus - Finaliteit Doorstroom" - file_info: "Leerlingencursus" - file_location: "/assets/files/care/AIindeZorg_doorstroom_eerstedruk.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Kaartenset (unplugged activiteit) - Ook verkrijgbaar in gedrukte versie" - file_info: "Aan de hand van deze kaartenset kan je de leerlingen laten stilstaan bij de ethische aspecten van nieuwe technologieën. Hoe zit het met privacy? Komen de sociale contacten niet in het gedrang? Welke technologieën worden met open armen ontvangen? Wat is niet wenselijk? Zijn de nieuwe technologieën voor iedereen betaalbaar?" - file_location: "/assets/files/care/Kaartset_AIIndeZorg_AIOpSchool_Dwengo.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Handleiding kaartenset" - file_info: "Deze handleiding voorziet extra uitleg bij de kaartenset." - file_location: "/assets/files/care/AIIndeZorgKaartenset_UitlegVoorLeerkracht.pdf" - file_icon_name: "description" - link_name: "Download" + file_location: '/assets/files/care/Sprouts.mov' + file_icon_name: 'play_arrow' + link_name: 'Download' + - file_title: 'Uitleg bij oefeningen grafen uit de leerlingencursus' + file_info: 'Welke figuren stellen er dezelfde graaf voor? Een meer formele werkwijze.​' + file_location: '/assets/files/care/dezelfdegraafFormeel.mov' + file_icon_name: 'play_arrow' + link_name: 'Download' + - file_title: 'Uitleg bij oefeningen grafen uit de leerlingencursus' + file_info: 'Welke figuren stellen er dezelfde graaf voor? Een werkwijze met kleuren.​' + file_location: '/assets/files/care/dezelfdeGraaf.mov' + file_icon_name: 'play_arrow' + link_name: 'Download' + - file_title: 'De leerlingencursus - Finaliteit Doorstroom' + file_info: 'Leerlingencursus' + file_location: '/assets/files/care/AIindeZorg_doorstroom_eerstedruk.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Kaartenset (unplugged activiteit) - Ook verkrijgbaar in gedrukte versie' + file_info: 'Aan de hand van deze kaartenset kan je de leerlingen laten stilstaan bij de ethische aspecten van nieuwe technologieën. Hoe zit het met privacy? Komen de sociale contacten niet in het gedrang? Welke technologieën worden met open armen ontvangen? Wat is niet wenselijk? Zijn de nieuwe technologieën voor iedereen betaalbaar?' + file_location: '/assets/files/care/Kaartset_AIIndeZorg_AIOpSchool_Dwengo.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Handleiding kaartenset' + file_info: 'Deze handleiding voorziet extra uitleg bij de kaartenset.' + file_location: '/assets/files/care/AIIndeZorgKaartenset_UitlegVoorLeerkracht.pdf' + file_icon_name: 'description' + link_name: 'Download' - file_title: "Beslissingsboom 'mBrAIn'-project in niet-compacte vorm" file_info: "In het onderzoeksproject 'mBrain', dat de ontwikkeling van een app die een migraineaanval voorspelt, als doel heeft, werd een beslissingsboom geconstrueerd. Met deze beslissingsboom wordt een probleem van binaire classificatie aangepakt: er zijn slechts twee klassen: ‘Migraine’ en ‘Geen migraine’. (Bronnen: Femke Ongenae. (2021), UGent; Van Hoecke, S., Ongenae, F., Paemeleire, K., & Vandenbussche, N. (2020). App moet hoofdpijn voorspellen. EOS Wetenschap Special, Technologie en gezondheid, 25.) Wij hebben de vorm van deze beslissingsboom omgevormd tot een binaire beslissingsboom om aan te tonen dat deze vorm niet altijd gebruiksvriendelijk is. Voor meer uitleg zie hoofdstuk 4 van de leerlingencursus van dit project.​" - file_location: "/assets/files/care/MBrainBeslissingsboom.png" - file_icon_name: "description" - link_name: "Download" - - file_title: "Zoektocht naar spraak - Computationeel denken (unplugged activiteit)" - file_info: "Het locked-in syndroom is een van de ergste medische aandoeningen. Je bent volledig verlamd, behalve dat je misschien nog kunt knipperen met een oog. Je intelligente geest zit opgesloten in een nutteloos lichaam: je kan alles voelen, maar niet communiceren. Het kan iedereen overkomen, uit het niets, als gevolg van een beroerte. Als je mensen met het locked-in syndroom zou willen helpen, word je dan best arts of verpleegkundige? Of kan je als computerwetenschapper ook helpen?​" - file_location: "/assets/files/care/ZoektochtNaarSpraak.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Sociale robots en stellingenspel (unplugged activiteit)" - file_info: "In deze presentatie maken leerlingen eerst kennis met sociale robots. Nadien worden de leerlingen aan de hand van enkele stellingen uitgedaagd om stil te staan bij de ethische aspecten van nieuwe technologieën.​ Hoe zit het met privacy? Komen de sociale contacten niet in het gedrang? Welke technologieën worden met open armen ontvangen? Wat is niet wenselijk? Zijn de nieuwe technologieën voor iedereen betaalbaar?" - file_location: "/assets/files/care/StellingenspelByDwengo.pdf" - file_icon_name: "description" - link_name: "Download" + file_location: '/assets/files/care/MBrainBeslissingsboom.png' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Zoektocht naar spraak - Computationeel denken (unplugged activiteit)' + file_info: 'Het locked-in syndroom is een van de ergste medische aandoeningen. Je bent volledig verlamd, behalve dat je misschien nog kunt knipperen met een oog. Je intelligente geest zit opgesloten in een nutteloos lichaam: je kan alles voelen, maar niet communiceren. Het kan iedereen overkomen, uit het niets, als gevolg van een beroerte. Als je mensen met het locked-in syndroom zou willen helpen, word je dan best arts of verpleegkundige? Of kan je als computerwetenschapper ook helpen?​' + file_location: '/assets/files/care/ZoektochtNaarSpraak.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Sociale robots en stellingenspel (unplugged activiteit)' + file_info: 'In deze presentatie maken leerlingen eerst kennis met sociale robots. Nadien worden de leerlingen aan de hand van enkele stellingen uitgedaagd om stil te staan bij de ethische aspecten van nieuwe technologieën.​ Hoe zit het met privacy? Komen de sociale contacten niet in het gedrang? Welke technologieën worden met open armen ontvangen? Wat is niet wenselijk? Zijn de nieuwe technologieën voor iedereen betaalbaar?' + file_location: '/assets/files/care/StellingenspelByDwengo.pdf' + file_icon_name: 'description' + link_name: 'Download' chatbot: title: Taaltechnologie sub_title: Aan de slag met een chatbot - description: "Waar taal en technologie samenkomen, ontstaat het domein van Natural Language Processing. Kan een computer teksten begrijpen, vertalen of zelfs schrijven? Kan een computer emoties herkennen? Leerlingen uit de tweede en derde graad (SO) leren er alles over in dit pakket." + description: 'Waar taal en technologie samenkomen, ontstaat het domein van Natural Language Processing. Kan een computer teksten begrijpen, vertalen of zelfs schrijven? Kan een computer emoties herkennen? Leerlingen uit de tweede en derde graad (SO) leren er alles over in dit pakket.' contact: Vragen? Contacteer ons via team@aiopschool.be. De pers kan contact opnemen met Francis wyffels via Francis@dwengo.org. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 curricula_files: - - file_title: "Projectfiche Chatbot" - file_info: "Dit is een kort overzicht van Chatbot-project met projectstructuur- en kenmerken." - file_location: "/assets/files/chatbot/projectfiche_chatbot.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "BrAInfood Chatbots" - file_info: "In deze brAInfood - gericht naar jongeren - geeft het Kenniscentrum Data & Maatschappij meer informatie over chatbots. De brAInfood bevat een fictief verhaal over Lotte die praat met een chatbot, en vermoedelijk informatie over haar doorgeeft aan bedrijven. Verder worden enkele aandachtspunten met betrekking tot chatbots toegelicht, alsook enkele tips voor jongeren om hun (persoons)gegevens beter te beschermen. Op die manier willen we jongeren bewuster maken van de werking van chatbots en hen stimuleren te reflecteren over de gegevens die van hen worden verzameld.​" - file_location: "/assets/files/chatbot/Brainfood13_Chatbots_NL.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "BrAInfood Gepersonaliseerde nieuwsberichten" - file_info: "In deze brAInfood van het Kenniscentrum Data & Maatschappij worden tips gegeven over hoe je de controle houdt over je newsfeed.​" - file_location: "/assets/files/chatbot/brainfoodaanbevelingnieuws.jpg" - file_icon_name: "description" - link_name: "Download" + - file_title: 'Projectfiche Chatbot' + file_info: 'Dit is een kort overzicht van Chatbot-project met projectstructuur- en kenmerken.' + file_location: '/assets/files/chatbot/projectfiche_chatbot.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'BrAInfood Chatbots' + file_info: 'In deze brAInfood - gericht naar jongeren - geeft het Kenniscentrum Data & Maatschappij meer informatie over chatbots. De brAInfood bevat een fictief verhaal over Lotte die praat met een chatbot, en vermoedelijk informatie over haar doorgeeft aan bedrijven. Verder worden enkele aandachtspunten met betrekking tot chatbots toegelicht, alsook enkele tips voor jongeren om hun (persoons)gegevens beter te beschermen. Op die manier willen we jongeren bewuster maken van de werking van chatbots en hen stimuleren te reflecteren over de gegevens die van hen worden verzameld.​' + file_location: '/assets/files/chatbot/Brainfood13_Chatbots_NL.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'BrAInfood Gepersonaliseerde nieuwsberichten' + file_info: 'In deze brAInfood van het Kenniscentrum Data & Maatschappij worden tips gegeven over hoe je de controle houdt over je newsfeed.​' + file_location: '/assets/files/chatbot/brainfoodaanbevelingnieuws.jpg' + file_icon_name: 'description' + link_name: 'Download' - file_title: "Handleiding 'Chatbot' - Ook verkrijgbaar in gedrukte versie" file_info: "​Leerkrachten verwerven via deze handleiding voldoende achtergrondinformatie om met (een deel van) het 'Chatbot'-project aan de slag te gaan in de klas. Het boek behandelt verschillende aspecten van taaltechnologie, zoals de geschiedenis van de artificiële intelligentie, de ethische aspecten ervan, sentimentanalyse en cyberpestdetectie, chatbots, sprekende digitale assistenten, en auteursherkenning. Er wordt ook ingegaan op de STEM-eindtermen en de eindtermen rond digitale competentie en mediawijsheid." - file_location: "/assets/files/chatbot/Chatbot_handleiding_eerstedruk.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Improbotics - Lesmap - Leerkrachtenversie" - file_info: "In de theatervoorstelling Improbotics improviseert een sociale robot mee in de scènes. In de lesmap vind je informatie over de gebruikte technologieën.​" - file_location: "/assets/files/chatbot/Improbotics_lesmap_Leerkracht.pdf" - file_icon_name: "description" - link_name: "Download" - - file_title: "Improbotics - Lesmap - Leerlingen" - file_info: "In de theatervoorstelling Improbotics improviseert een sociale robot mee in de scènes. In de lesmap vind je informatie over de gebruikte technologieën.​" - file_location: "/assets/files/chatbot/Improbotics_lesmap_Leerling.pdf" - file_icon_name: "description" - link_name: "Download" + file_location: '/assets/files/chatbot/Chatbot_handleiding_eerstedruk.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Improbotics - Lesmap - Leerkrachtenversie' + file_info: 'In de theatervoorstelling Improbotics improviseert een sociale robot mee in de scènes. In de lesmap vind je informatie over de gebruikte technologieën.​' + file_location: '/assets/files/chatbot/Improbotics_lesmap_Leerkracht.pdf' + file_icon_name: 'description' + link_name: 'Download' + - file_title: 'Improbotics - Lesmap - Leerlingen' + file_info: 'In de theatervoorstelling Improbotics improviseert een sociale robot mee in de scènes. In de lesmap vind je informatie over de gebruikte technologieën.​' + file_location: '/assets/files/chatbot/Improbotics_lesmap_Leerling.pdf' + file_icon_name: 'description' + link_name: 'Download' physical_computing: title: Physical computing sub_title: Programmeer robots in de klas - description: "Een muziekinstrument, auto of weerstation bouwen? Dat kan met Dwenguino, een microcontrollerplatform met een eigen programmeeromgeving. Leerlingen uit zowel basis- als secundair onderwijs kunnen er meteen mee aan de slag. In het echt of in onze simulator, blokgebaseerd of tekstueel. " + description: 'Een muziekinstrument, auto of weerstation bouwen? Dat kan met Dwenguino, een microcontrollerplatform met een eigen programmeeromgeving. Leerlingen uit zowel basis- als secundair onderwijs kunnen er meteen mee aan de slag. In het echt of in onze simulator, blokgebaseerd of tekstueel. ' contact: Vragen? Contacteer ons via team@aiopschool.be. De pers kan contact opnemen met Francis wyffels via Francis@dwengo.org. teaser: https://www.youtube.com/embed/tqSnpAKLsu8 curricula_files: - - file_title: "Bouw jouw eigen robot" - file_info: "Bouw je eigen rijdende robot." - file_location: "/assets/files/physical_computing/bouwjouweigenrobot.pdf" - file_icon_name: "description" - link_name: "Download" + - file_title: 'Bouw jouw eigen robot' + file_info: 'Bouw je eigen rijdende robot.' + file_location: '/assets/files/physical_computing/bouwjouweigenrobot.pdf' + file_icon_name: 'description' + link_name: 'Download' diff --git a/backend/src/app.ts b/backend/src/app.ts index b0f7afa2..f0d1b32e 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -15,7 +15,6 @@ import loginRouter from './routes/login'; const app: Express = express(); const port: string | number = getNumericEnvVar(EnvVars.Port); - // TODO Replace with Express routes app.get('/', (_, res: Response) => { res.json({ diff --git a/backend/src/entities/assignments/assignment.entity.ts b/backend/src/entities/assignments/assignment.entity.ts index 7909b107..89952c64 100644 --- a/backend/src/entities/assignments/assignment.entity.ts +++ b/backend/src/entities/assignments/assignment.entity.ts @@ -12,7 +12,12 @@ import { Language } from '../content/language.js'; @Entity() export class Assignment { - @ManyToOne({ entity: () => {return Class}, primary: true }) + @ManyToOne({ + entity: () => { + return Class; + }, + primary: true, + }) within!: Class; @PrimaryKey({ type: 'number' }) @@ -27,9 +32,18 @@ export class Assignment { @Property({ type: 'string' }) learningPathHruid!: string; - @Enum({ items: () => {return Language} }) + @Enum({ + items: () => { + return Language; + }, + }) learningPathLanguage!: Language; - @OneToMany({ entity: () => {return Group}, mappedBy: 'assignment' }) + @OneToMany({ + entity: () => { + return Group; + }, + mappedBy: 'assignment', + }) groups!: Group[]; } diff --git a/backend/src/entities/assignments/group.entity.ts b/backend/src/entities/assignments/group.entity.ts index a68eb5a0..5b224087 100644 --- a/backend/src/entities/assignments/group.entity.ts +++ b/backend/src/entities/assignments/group.entity.ts @@ -4,12 +4,21 @@ import { Student } from '../users/student.entity.js'; @Entity() export class Group { - @ManyToOne({ entity: () => {return Assignment}, primary: true }) + @ManyToOne({ + entity: () => { + return Assignment; + }, + primary: true, + }) assignment!: Assignment; @PrimaryKey({ type: 'integer' }) groupNumber!: number; - @ManyToMany({ entity: () => {return Student} }) + @ManyToMany({ + entity: () => { + return Student; + }, + }) members!: Student[]; } diff --git a/backend/src/entities/assignments/submission.entity.ts b/backend/src/entities/assignments/submission.entity.ts index bd0936a1..1bc28add 100644 --- a/backend/src/entities/assignments/submission.entity.ts +++ b/backend/src/entities/assignments/submission.entity.ts @@ -8,7 +8,12 @@ export class Submission { @PrimaryKey({ type: 'string' }) learningObjectHruid!: string; - @Enum({ items: () => {return Language}, primary: true }) + @Enum({ + items: () => { + return Language; + }, + primary: true, + }) learningObjectLanguage!: Language; @PrimaryKey({ type: 'string' }) @@ -17,13 +22,22 @@ export class Submission { @PrimaryKey({ type: 'integer' }) submissionNumber!: number; - @ManyToOne({ entity: () => {return Student} }) + @ManyToOne({ + entity: () => { + return Student; + }, + }) submitter!: Student; @Property({ type: 'datetime' }) submissionTime!: Date; - @ManyToOne({ entity: () => {return Group}, nullable: true }) + @ManyToOne({ + entity: () => { + return Group; + }, + nullable: true, + }) onBehalfOf?: Group; @Property({ type: 'json' }) diff --git a/backend/src/entities/classes/class-join-request.entity.ts b/backend/src/entities/classes/class-join-request.entity.ts index 8e88999c..2f9fc341 100644 --- a/backend/src/entities/classes/class-join-request.entity.ts +++ b/backend/src/entities/classes/class-join-request.entity.ts @@ -4,13 +4,25 @@ import { Class } from './class.entity'; @Entity() export class ClassJoinRequest { - @ManyToOne({ entity: () => {return Student}, primary: true }) + @ManyToOne({ + entity: () => { + return Student; + }, + primary: true, + }) requester!: Student; - @ManyToOne({ entity: () => {return Class}, primary: true }) + @ManyToOne({ + entity: () => { + return Class; + }, + primary: true, + }) class!: Class; - @Enum(() => {return ClassJoinRequestStatus}) + @Enum(() => { + return ClassJoinRequestStatus; + }) status!: ClassJoinRequestStatus; } diff --git a/backend/src/entities/classes/class.entity.ts b/backend/src/entities/classes/class.entity.ts index 2ad98c84..ecc11748 100644 --- a/backend/src/entities/classes/class.entity.ts +++ b/backend/src/entities/classes/class.entity.ts @@ -17,9 +17,13 @@ export class Class { @Property({ type: 'string' }) displayName!: string; - @ManyToMany(() => {return Teacher}) + @ManyToMany(() => { + return Teacher; + }) teachers!: Collection; - @ManyToMany(() => {return Student}) + @ManyToMany(() => { + return Student; + }) students!: Collection; } diff --git a/backend/src/entities/classes/teacher-invitation.entity.ts b/backend/src/entities/classes/teacher-invitation.entity.ts index feba8fc3..98d2bdd4 100644 --- a/backend/src/entities/classes/teacher-invitation.entity.ts +++ b/backend/src/entities/classes/teacher-invitation.entity.ts @@ -7,12 +7,27 @@ import { Class } from './class.entity.js'; */ @Entity() export class TeacherInvitation { - @ManyToOne({ entity: () => {return Teacher}, primary: true }) + @ManyToOne({ + entity: () => { + return Teacher; + }, + primary: true, + }) sender!: Teacher; - @ManyToOne({ entity: () => {return Teacher}, primary: true }) + @ManyToOne({ + entity: () => { + return Teacher; + }, + primary: true, + }) receiver!: Teacher; - @ManyToOne({ entity: () => {return Class}, primary: true }) + @ManyToOne({ + entity: () => { + return Class; + }, + primary: true, + }) class!: Class; } diff --git a/backend/src/entities/content/attachment.entity.ts b/backend/src/entities/content/attachment.entity.ts index 2ead7262..7a9dd946 100644 --- a/backend/src/entities/content/attachment.entity.ts +++ b/backend/src/entities/content/attachment.entity.ts @@ -3,7 +3,12 @@ import { LearningObject } from './learning-object.entity.js'; @Entity() export class Attachment { - @ManyToOne({ entity: () => {return LearningObject}, primary: true }) + @ManyToOne({ + entity: () => { + return LearningObject; + }, + primary: true, + }) learningObject!: LearningObject; @PrimaryKey({ type: 'integer' }) diff --git a/backend/src/entities/content/learning-object.entity.ts b/backend/src/entities/content/learning-object.entity.ts index c5bfe08f..bf499e8a 100644 --- a/backend/src/entities/content/learning-object.entity.ts +++ b/backend/src/entities/content/learning-object.entity.ts @@ -17,13 +17,22 @@ export class LearningObject { @PrimaryKey({ type: 'string' }) hruid!: string; - @Enum({ items: () => {return Language}, primary: true }) + @Enum({ + items: () => { + return Language; + }, + primary: true, + }) language!: Language; @PrimaryKey({ type: 'string' }) version: string = '1'; - @ManyToMany({ entity: () => {return Teacher} }) + @ManyToMany({ + entity: () => { + return Teacher; + }, + }) admins!: Teacher[]; @Property({ type: 'string' }) @@ -47,7 +56,12 @@ export class LearningObject { @Property({ type: 'array' }) skosConcepts!: string[]; - @Embedded({ entity: () => {return EducationalGoal}, array: true }) + @Embedded({ + entity: () => { + return EducationalGoal; + }, + array: true, + }) educationalGoals: EducationalGoal[] = []; @Property({ type: 'string' }) @@ -62,7 +76,11 @@ export class LearningObject { @Property({ type: 'integer' }) estimatedTime!: number; - @Embedded({ entity: () => {return ReturnValue} }) + @Embedded({ + entity: () => { + return ReturnValue; + }, + }) returnValue!: ReturnValue; @Property({ type: 'bool' }) @@ -71,7 +89,12 @@ export class LearningObject { @Property({ type: 'string', nullable: true }) contentLocation?: string; - @OneToMany({ entity: () => {return Attachment}, mappedBy: 'learningObject' }) + @OneToMany({ + entity: () => { + return Attachment; + }, + mappedBy: 'learningObject', + }) attachments: Attachment[] = []; @Property({ type: 'blob' }) diff --git a/backend/src/entities/content/learning-path.entity.ts b/backend/src/entities/content/learning-path.entity.ts index f758dace..28d3cadd 100644 --- a/backend/src/entities/content/learning-path.entity.ts +++ b/backend/src/entities/content/learning-path.entity.ts @@ -16,10 +16,19 @@ export class LearningPath { @PrimaryKey({ type: 'string' }) hruid!: string; - @Enum({ items: () => {return Language}, primary: true }) + @Enum({ + items: () => { + return Language; + }, + primary: true, + }) language!: Language; - @ManyToMany({ entity: () => {return Teacher} }) + @ManyToMany({ + entity: () => { + return Teacher; + }, + }) admins!: Teacher[]; @Property({ type: 'string' }) @@ -31,7 +40,12 @@ export class LearningPath { @Property({ type: 'blob' }) image!: string; - @Embedded({ entity: () => {return LearningPathNode}, array: true }) + @Embedded({ + entity: () => { + return LearningPathNode; + }, + array: true, + }) nodes: LearningPathNode[] = []; } @@ -40,7 +54,11 @@ export class LearningPathNode { @Property({ type: 'string' }) learningObjectHruid!: string; - @Enum({ items: () => {return Language} }) + @Enum({ + items: () => { + return Language; + }, + }) language!: Language; @Property({ type: 'string' }) @@ -52,7 +70,12 @@ export class LearningPathNode { @Property({ type: 'bool' }) startNode!: boolean; - @Embedded({ entity: () => {return LearningPathTransition}, array: true }) + @Embedded({ + entity: () => { + return LearningPathTransition; + }, + array: true, + }) transitions!: LearningPathTransition[]; } @@ -61,6 +84,10 @@ export class LearningPathTransition { @Property({ type: 'string' }) condition!: string; - @OneToOne({ entity: () => {return LearningPathNode} }) + @OneToOne({ + entity: () => { + return LearningPathNode; + }, + }) next!: LearningPathNode; } diff --git a/backend/src/entities/questions/answer.entity.ts b/backend/src/entities/questions/answer.entity.ts index 2690d50d..34558612 100644 --- a/backend/src/entities/questions/answer.entity.ts +++ b/backend/src/entities/questions/answer.entity.ts @@ -4,10 +4,20 @@ import { Teacher } from '../users/teacher.entity'; @Entity() export class Answer { - @ManyToOne({ entity: () => {return Teacher}, primary: true }) + @ManyToOne({ + entity: () => { + return Teacher; + }, + primary: true, + }) author!: Teacher; - @ManyToOne({ entity: () => {return Question}, primary: true }) + @ManyToOne({ + entity: () => { + return Question; + }, + primary: true, + }) toQuestion!: Question; @PrimaryKey({ type: 'integer' }) diff --git a/backend/src/entities/questions/question.entity.ts b/backend/src/entities/questions/question.entity.ts index 5830c816..444d2179 100644 --- a/backend/src/entities/questions/question.entity.ts +++ b/backend/src/entities/questions/question.entity.ts @@ -7,7 +7,12 @@ export class Question { @PrimaryKey({ type: 'string' }) learningObjectHruid!: string; - @Enum({ items: () => {return Language}, primary: true }) + @Enum({ + items: () => { + return Language; + }, + primary: true, + }) learningObjectLanguage!: Language; @PrimaryKey({ type: 'string' }) @@ -16,7 +21,11 @@ export class Question { @PrimaryKey({ type: 'integer' }) sequenceNumber!: number; - @ManyToOne({ entity: () => {return Student} }) + @ManyToOne({ + entity: () => { + return Student; + }, + }) author!: Student; @Property({ type: 'datetime' }) diff --git a/backend/src/entities/users/student.entity.ts b/backend/src/entities/users/student.entity.ts index ccfa7dfc..c5632e84 100644 --- a/backend/src/entities/users/student.entity.ts +++ b/backend/src/entities/users/student.entity.ts @@ -4,12 +4,20 @@ import { Class } from '../classes/class.entity.js'; import { Group } from '../assignments/group.entity.js'; import { StudentRepository } from '../../data/users/student-repository.js'; -@Entity({ repository: () => {return StudentRepository} }) +@Entity({ + repository: () => { + return StudentRepository; + }, +}) export class Student extends User { - @ManyToMany(() => {return Class}) + @ManyToMany(() => { + return Class; + }) classes!: Collection; - @ManyToMany(() => {return Group}) + @ManyToMany(() => { + return Group; + }) groups!: Collection; constructor( diff --git a/backend/src/entities/users/teacher.entity.ts b/backend/src/entities/users/teacher.entity.ts index eaaa8327..9f11a3b0 100644 --- a/backend/src/entities/users/teacher.entity.ts +++ b/backend/src/entities/users/teacher.entity.ts @@ -4,6 +4,8 @@ import { Class } from '../classes/class.entity.js'; @Entity() export class Teacher extends User { - @ManyToMany(() => {return Class}) + @ManyToMany(() => { + return Class; + }) classes!: Collection; } diff --git a/backend/src/mikro-orm.config.ts b/backend/src/mikro-orm.config.ts index 88996cf9..d180bce0 100644 --- a/backend/src/mikro-orm.config.ts +++ b/backend/src/mikro-orm.config.ts @@ -15,21 +15,22 @@ function config(testingMode: boolean = false): Options { // Workaround: vitest: `TypeError: Unknown file extension ".ts"` (ERR_UNKNOWN_FILE_EXTENSION) // (see https://mikro-orm.io/docs/guide/project-setup#testing-the-endpoint) - dynamicImportProvider: (id) => {return import(id)}, + dynamicImportProvider: (id) => { + return import(id); + }, }; - } - return { - driver: PostgreSqlDriver, - host: getEnvVar(EnvVars.DbHost), - port: getNumericEnvVar(EnvVars.DbPort), - dbName: getEnvVar(EnvVars.DbName), - user: getEnvVar(EnvVars.DbUsername), - password: getEnvVar(EnvVars.DbPassword), - entities: entities, - entitiesTs: entitiesTs, - debug: true, - }; - + } + return { + driver: PostgreSqlDriver, + host: getEnvVar(EnvVars.DbHost), + port: getNumericEnvVar(EnvVars.DbPort), + dbName: getEnvVar(EnvVars.DbName), + user: getEnvVar(EnvVars.DbUsername), + password: getEnvVar(EnvVars.DbPassword), + entities: entities, + entitiesTs: entitiesTs, + debug: true, + }; } export default config; diff --git a/backend/src/routes/assignment.ts b/backend/src/routes/assignment.ts index eb49144f..4ae5756d 100644 --- a/backend/src/routes/assignment.ts +++ b/backend/src/routes/assignment.ts @@ -1,13 +1,10 @@ -import express from 'express' +import express from 'express'; const router = express.Router(); // Root endpoint used to search objects router.get('/', (req, res) => { res.json({ - assignments: [ - '0', - '1', - ] + assignments: ['0', '1'], }); }); @@ -17,7 +14,7 @@ router.get('/:id', (req, res) => { id: req.params.id, title: 'Dit is een test assignment', description: 'Een korte beschrijving', - groups: [ '0' ], + groups: ['0'], learningPath: '0', class: '0', links: { @@ -25,30 +22,24 @@ router.get('/:id', (req, res) => { submissions: `${req.baseUrl}/${req.params.id}`, }, }); -}) +}); router.get('/:id/submissions', (req, res) => { res.json({ - submissions: [ - '0' - ], + submissions: ['0'], }); }); router.get('/:id/groups', (req, res) => { res.json({ - groups: [ - '0' - ], + groups: ['0'], }); }); router.get('/:id/questions', (req, res) => { res.json({ - questions: [ - '0' - ], + questions: ['0'], }); }); -export default router \ No newline at end of file +export default router; diff --git a/backend/src/routes/class.ts b/backend/src/routes/class.ts index fa7a2310..6f8f324e 100644 --- a/backend/src/routes/class.ts +++ b/backend/src/routes/class.ts @@ -1,13 +1,10 @@ -import express from 'express' +import express from 'express'; const router = express.Router(); // Root endpoint used to search objects router.get('/', (req, res) => { res.json({ - classes: [ - '0', - '1', - ] + classes: ['0', '1'], }); }); @@ -16,40 +13,34 @@ router.get('/:id', (req, res) => { res.json({ id: req.params.id, displayName: 'Klas 4B', - teachers: [ '0' ], - students: [ '0' ], - joinRequests: [ '0' ], + teachers: ['0'], + students: ['0'], + joinRequests: ['0'], links: { self: `${req.baseUrl}/${req.params.id}`, classes: `${req.baseUrl}/${req.params.id}/invitations`, questions: `${req.baseUrl}/${req.params.id}/assignments`, students: `${req.baseUrl}/${req.params.id}/students`, - } + }, }); -}) +}); router.get('/:id/invitations', (req, res) => { res.json({ - invitations: [ - '0' - ], + invitations: ['0'], }); -}) +}); router.get('/:id/assignments', (req, res) => { res.json({ - assignments: [ - '0' - ], + assignments: ['0'], }); -}) +}); router.get('/:id/students', (req, res) => { res.json({ - students: [ - '0' - ], + students: ['0'], }); -}) +}); -export default router \ No newline at end of file +export default router; diff --git a/backend/src/routes/group.ts b/backend/src/routes/group.ts index e951a8a7..303f5215 100644 --- a/backend/src/routes/group.ts +++ b/backend/src/routes/group.ts @@ -1,13 +1,10 @@ -import express from 'express' +import express from 'express'; const router = express.Router(); // Root endpoint used to search objects router.get('/', (req, res) => { res.json({ - groups: [ - '0', - '1', - ] + groups: ['0', '1'], }); }); @@ -16,19 +13,19 @@ router.get('/:id', (req, res) => { res.json({ id: req.params.id, assignment: '0', - students: [ '0' ], - submissions: [ '0' ], + students: ['0'], + submissions: ['0'], // Reference to other endpoint // Should be less hardcoded - questions: `/group/${req.params.id}/question`, + questions: `/group/${req.params.id}/question`, }); -}) +}); // The list of questions a group has made router.get('/:id/question', (req, res) => { res.json({ - questions: [ '0' ], + questions: ['0'], }); -}) +}); -export default router \ No newline at end of file +export default router; diff --git a/backend/src/routes/login.ts b/backend/src/routes/login.ts index bc2ed3d8..33d5e6c3 100644 --- a/backend/src/routes/login.ts +++ b/backend/src/routes/login.ts @@ -1,4 +1,4 @@ -import express from 'express' +import express from 'express'; const router = express.Router(); // Returns login paths for IDP @@ -9,6 +9,6 @@ router.get('/', (req, res) => { leerkracht: '/login-leerkracht', leerling: '/login-leerling', }); -}) +}); -export default router \ No newline at end of file +export default router; diff --git a/backend/src/routes/question.ts b/backend/src/routes/question.ts index 040f742d..f683d998 100644 --- a/backend/src/routes/question.ts +++ b/backend/src/routes/question.ts @@ -1,13 +1,10 @@ -import express from 'express' +import express from 'express'; const router = express.Router(); // Root endpoint used to search objects router.get('/', (req, res) => { res.json({ - questions: [ - '0', - '1', - ] + questions: ['0', '1'], }); }); @@ -18,21 +15,20 @@ router.get('/:id', (req, res) => { student: '0', group: '0', time: new Date(2025, 1, 1), - content: 'Zijn alle gehele getallen groter dan 2 gelijk aan de som van 2 priemgetallen????', + content: + 'Zijn alle gehele getallen groter dan 2 gelijk aan de som van 2 priemgetallen????', learningObject: '0', links: { self: `${req.baseUrl}/${req.params.id}`, answers: `${req.baseUrl}/${req.params.id}/answers`, - } + }, }); -}) +}); router.get('/:id/answers', (req, res) => { res.json({ - answers: [ - '0' - ], - }) -}) + answers: ['0'], + }); +}); -export default router \ No newline at end of file +export default router; diff --git a/backend/src/routes/student.ts b/backend/src/routes/student.ts index bc3f588b..9cb0cdee 100644 --- a/backend/src/routes/student.ts +++ b/backend/src/routes/student.ts @@ -1,13 +1,10 @@ -import express from 'express' +import express from 'express'; const router = express.Router(); // Root endpoint used to search objects router.get('/', (req, res) => { res.json({ - students: [ - '0', - '1', - ] + students: ['0', '1'], }); }); @@ -30,30 +27,29 @@ router.get('/:id', (req, res) => { // The list of classes a student is in router.get('/:id/classes', (req, res) => { res.json({ - classes: [ '0' ], + classes: ['0'], }); -}) +}); // The list of submissions a student has made router.get('/:id/submissions', (req, res) => { res.json({ - submissions: [ '0' ], + submissions: ['0'], }); -}) +}); - // The list of assignments a student has router.get('/:id/assignments', (req, res) => { res.json({ - assignments: [ '0' ], + assignments: ['0'], }); -}) - +}); + // The list of groups a student is in router.get('/:id/groups', (req, res) => { res.json({ - groups: [ '0' ], + groups: ['0'], }); -}) +}); -export default router \ No newline at end of file +export default router; diff --git a/backend/src/routes/submission.ts b/backend/src/routes/submission.ts index 98acc842..cb4d3e85 100644 --- a/backend/src/routes/submission.ts +++ b/backend/src/routes/submission.ts @@ -1,13 +1,10 @@ -import express from 'express' +import express from 'express'; const router = express.Router(); // Root endpoint used to search objects router.get('/', (req, res) => { res.json({ - submissions: [ - '0', - '1', - ] + submissions: ['0', '1'], }); }); @@ -21,6 +18,6 @@ router.get('/:id', (req, res) => { content: 'Wortel 2 is rationeel', learningObject: '0', }); -}) +}); -export default router \ No newline at end of file +export default router; diff --git a/backend/src/routes/teacher.ts b/backend/src/routes/teacher.ts index f9de3aa5..a7c60bc9 100644 --- a/backend/src/routes/teacher.ts +++ b/backend/src/routes/teacher.ts @@ -1,13 +1,10 @@ -import express from 'express' +import express from 'express'; const router = express.Router(); // Root endpoint used to search objects router.get('/', (req, res) => { res.json({ - teachers: [ - '0', - '1', - ] + teachers: ['0', '1'], }); }); @@ -25,34 +22,27 @@ router.get('/:id', (req, res) => { invitations: `${req.baseUrl}/${req.params.id}/invitations`, }, }); -}) +}); // The questions students asked a teacher router.get('/:id/questions', (req, res) => { res.json({ - questions: [ - '0' - ], + questions: ['0'], }); }); // Invitations to other classes a teacher received router.get('/:id/invitations', (req, res) => { res.json({ - invitations: [ - '0' - ], + invitations: ['0'], }); }); // A list with ids of classes a teacher is in router.get('/:id/classes', (req, res) => { res.json({ - classes: [ - '0' - ], + classes: ['0'], }); }); - -export default router \ No newline at end of file +export default router; diff --git a/backend/tests/data/users.test.ts b/backend/tests/data/users.test.ts index a982151e..887748a2 100644 --- a/backend/tests/data/users.test.ts +++ b/backend/tests/data/users.test.ts @@ -1,13 +1,13 @@ -import {setupTestApp} from "../setup-tests.js" -import {Student} from "../../src/entities/users/student.entity.js"; -import {describe, it, expect, beforeAll} from "vitest"; -import {StudentRepository} from "../../src/data/users/student-repository.js"; -import {getStudentRepository} from "../../src/data/repositories.js"; +import { setupTestApp } from '../setup-tests.js'; +import { Student } from '../../src/entities/users/student.entity.js'; +import { describe, it, expect, beforeAll } from 'vitest'; +import { StudentRepository } from '../../src/data/users/student-repository.js'; +import { getStudentRepository } from '../../src/data/repositories.js'; -const username = "teststudent"; -const firstName = "John"; -const lastName = "Doe"; -describe("StudentRepository", () => { +const username = 'teststudent'; +const firstName = 'John'; +const lastName = 'Doe'; +describe('StudentRepository', () => { let studentRepository: StudentRepository; beforeAll(async () => { @@ -15,19 +15,23 @@ describe("StudentRepository", () => { studentRepository = getStudentRepository(); }); - it("should return the queried student after he was added", async () => { - await studentRepository.insert(new Student(username, firstName, lastName)); + it('should return the queried student after he was added', async () => { + await studentRepository.insert( + new Student(username, firstName, lastName) + ); - const retrievedStudent = await studentRepository.findByUsername(username); + const retrievedStudent = + await studentRepository.findByUsername(username); expect(retrievedStudent).toBeTruthy(); expect(retrievedStudent?.firstName).toBe(firstName); expect(retrievedStudent?.lastName).toBe(lastName); }); - it("should no longer return the queried student after he was removed again", async () => { + it('should no longer return the queried student after he was removed again', async () => { await studentRepository.deleteByUsername(username); - const retrievedStudent = await studentRepository.findByUsername(username); + const retrievedStudent = + await studentRepository.findByUsername(username); expect(retrievedStudent).toBeNull(); }); }); diff --git a/backend/tests/setup-tests.ts b/backend/tests/setup-tests.ts index 6738ad56..6c9d23f6 100644 --- a/backend/tests/setup-tests.ts +++ b/backend/tests/setup-tests.ts @@ -1,7 +1,7 @@ -import {initORM} from "../src/orm.js"; -import dotenv from "dotenv"; +import { initORM } from '../src/orm.js'; +import dotenv from 'dotenv'; export async function setupTestApp() { - dotenv.config({path: ".env.test"}); + dotenv.config({ path: '.env.test' }); await initORM(true); } diff --git a/backend/vitest.config.ts b/backend/vitest.config.ts index 7601a84b..302015fb 100644 --- a/backend/vitest.config.ts +++ b/backend/vitest.config.ts @@ -3,6 +3,6 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { environment: 'node', - globals: true - } + globals: true, + }, }); diff --git a/docker-compose.yml b/docker-compose.yml index c5230d7c..6be29180 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,14 +1,14 @@ services: - db: - image: postgres:latest - environment: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: postgres - ports: - - "5431:5432" - volumes: - - postgres_data:/var/lib/postgresql/data + db: + image: postgres:latest + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + - '5431:5432' + volumes: + - postgres_data:/var/lib/postgresql/data volumes: postgres_data: diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 7db110de..50d132d6 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,10 +1,7 @@ - + - + diff --git a/frontend/src/components/BrowseThemes.vue b/frontend/src/components/BrowseThemes.vue index 5191a920..9575da5f 100644 --- a/frontend/src/components/BrowseThemes.vue +++ b/frontend/src/components/BrowseThemes.vue @@ -1,11 +1,9 @@ - + diff --git a/frontend/src/components/LearningPath.vue b/frontend/src/components/LearningPath.vue index 4aaf6ef8..1a35a59f 100644 --- a/frontend/src/components/LearningPath.vue +++ b/frontend/src/components/LearningPath.vue @@ -1,11 +1,7 @@ - + - + diff --git a/frontend/src/components/MenuBar.vue b/frontend/src/components/MenuBar.vue index 73336fa3..1a35a59f 100644 --- a/frontend/src/components/MenuBar.vue +++ b/frontend/src/components/MenuBar.vue @@ -1,11 +1,7 @@ - + - + diff --git a/frontend/src/components/errors/NotFound.vue b/frontend/src/components/errors/NotFound.vue index 7a45fea2..99afde41 100644 --- a/frontend/src/components/errors/NotFound.vue +++ b/frontend/src/components/errors/NotFound.vue @@ -1,11 +1,7 @@ - + - + diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index 8ce0fe3f..558d88e7 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -1,4 +1,4 @@ -import {createRouter, createWebHistory} from "vue-router"; +import { createRouter, createWebHistory } from "vue-router"; import MenuBar from "@/components/MenuBar.vue"; import StudentHomepage from "@/views/StudentHomepage.vue"; import StudentAssignments from "@/views/assignments/StudentAssignments.vue"; @@ -22,12 +22,16 @@ const router = createRouter({ { path: "/", name: "home", - component: () => {return import("../views/HomePage.vue")}, + component: () => { + return import("../views/HomePage.vue"); + }, }, { path: "/login", name: "LoginPage", - component: () => {return import("../views/LoginPage.vue")} + component: () => { + return import("../views/LoginPage.vue"); + }, }, { path: "/student/:id", @@ -36,24 +40,24 @@ const router = createRouter({ { path: "home", name: "StudentHomePage", - component: StudentHomepage + component: StudentHomepage, }, { path: "assignment", name: "StudentAssignments", - component: StudentAssignments + component: StudentAssignments, }, { path: "class", name: "StudentClasses", - component: StudentClasses + component: StudentClasses, }, { path: "discussion", name: "StudentDiscussions", - component: StudentDiscussions + component: StudentDiscussions, }, - ] + ], }, { @@ -63,56 +67,54 @@ const router = createRouter({ { path: "home", name: "TeacherHomepage", - component: TeacherHomepage + component: TeacherHomepage, }, { path: "assignment", name: "TeacherAssignments", - component: TeacherAssignments + component: TeacherAssignments, }, { path: "class", name: "TeacherClasses", - component: TeacherClasses + component: TeacherClasses, }, { path: "discussion", name: "TeacherDiscussions", - component: TeacherDiscussions + component: TeacherDiscussions, }, - ] + ], }, { path: "/assignment/create", name: "CreateAssigment", - component: CreateAssignment - + component: CreateAssignment, }, { path: "/assignment/:id", name: "SingleAssigment", - component: SingleAssignment - + component: SingleAssignment, }, { path: "/class/create", name: "CreateClass", - component: CreateClass + component: CreateClass, }, { path: "/class/:id", name: "SingleClass", - component: SingleClass + component: SingleClass, }, { path: "/discussion/create", name: "CreateDiscussion", - component: CreateDiscussion + component: CreateDiscussion, }, { path: "/discussion/:id", name: "SingleDiscussion", - component: SingleDiscussion + component: SingleDiscussion, }, { path: "/:catchAll(.*)", diff --git a/frontend/src/views/HomePage.vue b/frontend/src/views/HomePage.vue index 677f16f0..60afc9ac 100644 --- a/frontend/src/views/HomePage.vue +++ b/frontend/src/views/HomePage.vue @@ -1,12 +1,8 @@ - + - + diff --git a/frontend/src/views/LoginPage.vue b/frontend/src/views/LoginPage.vue index 85a69bfd..1a35a59f 100644 --- a/frontend/src/views/LoginPage.vue +++ b/frontend/src/views/LoginPage.vue @@ -1,10 +1,7 @@ - + - + diff --git a/frontend/src/views/StudentHomepage.vue b/frontend/src/views/StudentHomepage.vue index 4aaf6ef8..1a35a59f 100644 --- a/frontend/src/views/StudentHomepage.vue +++ b/frontend/src/views/StudentHomepage.vue @@ -1,11 +1,7 @@ - + - + diff --git a/frontend/src/views/TeacherHomepage.vue b/frontend/src/views/TeacherHomepage.vue index 4aaf6ef8..1a35a59f 100644 --- a/frontend/src/views/TeacherHomepage.vue +++ b/frontend/src/views/TeacherHomepage.vue @@ -1,11 +1,7 @@ - + - + diff --git a/frontend/src/views/assignments/CreateAssignment.vue b/frontend/src/views/assignments/CreateAssignment.vue index 4aaf6ef8..1a35a59f 100644 --- a/frontend/src/views/assignments/CreateAssignment.vue +++ b/frontend/src/views/assignments/CreateAssignment.vue @@ -1,11 +1,7 @@ - + - + diff --git a/frontend/src/views/assignments/SingleAssignment.vue b/frontend/src/views/assignments/SingleAssignment.vue index 4aaf6ef8..1a35a59f 100644 --- a/frontend/src/views/assignments/SingleAssignment.vue +++ b/frontend/src/views/assignments/SingleAssignment.vue @@ -1,11 +1,7 @@ - + - + diff --git a/frontend/src/views/assignments/StudentAssignments.vue b/frontend/src/views/assignments/StudentAssignments.vue index 4aaf6ef8..1a35a59f 100644 --- a/frontend/src/views/assignments/StudentAssignments.vue +++ b/frontend/src/views/assignments/StudentAssignments.vue @@ -1,11 +1,7 @@ - + - + diff --git a/frontend/src/views/assignments/TeacherAssignments.vue b/frontend/src/views/assignments/TeacherAssignments.vue index 4aaf6ef8..1a35a59f 100644 --- a/frontend/src/views/assignments/TeacherAssignments.vue +++ b/frontend/src/views/assignments/TeacherAssignments.vue @@ -1,11 +1,7 @@ - + - + diff --git a/frontend/src/views/classes/CreateClass.vue b/frontend/src/views/classes/CreateClass.vue index 4aaf6ef8..1a35a59f 100644 --- a/frontend/src/views/classes/CreateClass.vue +++ b/frontend/src/views/classes/CreateClass.vue @@ -1,11 +1,7 @@ - + - + diff --git a/frontend/src/views/classes/SingleClass.vue b/frontend/src/views/classes/SingleClass.vue index 4aaf6ef8..1a35a59f 100644 --- a/frontend/src/views/classes/SingleClass.vue +++ b/frontend/src/views/classes/SingleClass.vue @@ -1,11 +1,7 @@ - + - + diff --git a/frontend/src/views/classes/StudentClasses.vue b/frontend/src/views/classes/StudentClasses.vue index 4aaf6ef8..1a35a59f 100644 --- a/frontend/src/views/classes/StudentClasses.vue +++ b/frontend/src/views/classes/StudentClasses.vue @@ -1,11 +1,7 @@ - + - + diff --git a/frontend/src/views/classes/TeacherClasses.vue b/frontend/src/views/classes/TeacherClasses.vue index 4aaf6ef8..1a35a59f 100644 --- a/frontend/src/views/classes/TeacherClasses.vue +++ b/frontend/src/views/classes/TeacherClasses.vue @@ -1,11 +1,7 @@ - + - + diff --git a/frontend/src/views/discussions/CreateDiscussion.vue b/frontend/src/views/discussions/CreateDiscussion.vue index 4aaf6ef8..1a35a59f 100644 --- a/frontend/src/views/discussions/CreateDiscussion.vue +++ b/frontend/src/views/discussions/CreateDiscussion.vue @@ -1,11 +1,7 @@ - + - + diff --git a/frontend/src/views/discussions/SingleDiscussion.vue b/frontend/src/views/discussions/SingleDiscussion.vue index 4aaf6ef8..1a35a59f 100644 --- a/frontend/src/views/discussions/SingleDiscussion.vue +++ b/frontend/src/views/discussions/SingleDiscussion.vue @@ -1,11 +1,7 @@ - + - + diff --git a/frontend/src/views/discussions/StudentDiscussions.vue b/frontend/src/views/discussions/StudentDiscussions.vue index 4aaf6ef8..1a35a59f 100644 --- a/frontend/src/views/discussions/StudentDiscussions.vue +++ b/frontend/src/views/discussions/StudentDiscussions.vue @@ -1,11 +1,7 @@ - + - + diff --git a/frontend/src/views/discussions/TeacherDiscussions.vue b/frontend/src/views/discussions/TeacherDiscussions.vue index 4aaf6ef8..1a35a59f 100644 --- a/frontend/src/views/discussions/TeacherDiscussions.vue +++ b/frontend/src/views/discussions/TeacherDiscussions.vue @@ -1,11 +1,7 @@ - + - + From be667c7c537485cfed082c37a27ecb87205f46c5 Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Sat, 1 Mar 2025 23:09:42 +0100 Subject: [PATCH 024/180] =?UTF-8?q?feat(backend):=20Auth=20middleware=20to?= =?UTF-8?q?egevoegd.=20Deze=20verifi=C3=ABert=20het=20meegegeven=20bearer?= =?UTF-8?q?=20token.=20Door=20een=20specifieke=20extra=20middleware=20per?= =?UTF-8?q?=20endpoint=20kan=20dan=20aangegeven=20worden=20of=20deze=20enk?= =?UTF-8?q?el=20toegankelijk=20is=20voor=20leerlingen,=20leerkrachten=20of?= =?UTF-8?q?=20allebei.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/.env.development.example | 5 + backend/package.json | 2 + backend/src/app.ts | 3 + backend/src/middleware/auth/auth.ts | 75 + .../middleware/auth/authenticated-request.ts | 6 + backend/src/routes/student.ts | 6 +- backend/src/util/envvars.ts | 8 + docker-compose.yml | 20 +- package-lock.json | 3386 +++-------------- 9 files changed, 722 insertions(+), 2789 deletions(-) create mode 100644 backend/src/middleware/auth/auth.ts create mode 100644 backend/src/middleware/auth/authenticated-request.ts diff --git a/backend/.env.development.example b/backend/.env.development.example index 58694df4..0b96f873 100644 --- a/backend/.env.development.example +++ b/backend/.env.development.example @@ -4,3 +4,8 @@ DWENGO_DB_PORT=5431 DWENGO_DB_USERNAME=postgres DWENGO_DB_PASSWORD=postgres DWENGO_DB_UPDATE=true + +DWENGO_AUTH_STUDENT_URL=http://localhost:7080/realms/student +DWENGO_AUTH_STUDENT_JWKS_ENDPOINT=http://localhost:7080/realms/student/protocol/openid-connect/certs +DWENGO_AUTH_TEACHER_URL=http://localhost:7080/realms/teacher +DWENGO_AUTH_TEACHER_JWKS_ENDPOINT=http://localhost:7080/realms/teacher/protocol/openid-connect/certs diff --git a/backend/package.json b/backend/package.json index 2b04044f..af8090f2 100644 --- a/backend/package.json +++ b/backend/package.json @@ -20,6 +20,8 @@ "@mikro-orm/reflection": "6.4.6", "dotenv": "^16.4.7", "express": "^5.0.1", + "express-jwt": "^8.5.1", + "jwks-rsa": "^3.1.0", "uuid": "^11.1.0", "js-yaml": "^4.1.0", "@types/js-yaml": "^4.0.9" diff --git a/backend/src/app.ts b/backend/src/app.ts index 7a25fa2b..521c40c5 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -11,6 +11,7 @@ import submissionRouter from './routes/submission.js'; import classRouter from './routes/class.js'; import questionRouter from './routes/question.js'; import loginRouter from './routes/login.js'; +import {authenticateUser} from "./middleware/auth/auth"; const app: Express = express(); const port: string | number = getNumericEnvVar(EnvVars.Port); @@ -23,6 +24,8 @@ app.get('/', (_, res: Response) => { }); }); +app.use(authenticateUser); + app.use('/student', studentRouter); app.use('/group', groupRouter); app.use('/assignment', assignmentRouter); diff --git a/backend/src/middleware/auth/auth.ts b/backend/src/middleware/auth/auth.ts new file mode 100644 index 00000000..82f1b23f --- /dev/null +++ b/backend/src/middleware/auth/auth.ts @@ -0,0 +1,75 @@ +import {EnvVars, getEnvVar} from "../../util/envvars.js"; +import {expressjwt} from 'express-jwt'; +import {JwtPayload} from 'jsonwebtoken' +import jwksClient from 'jwks-rsa'; +import * as express from "express"; +import * as jwt from "jsonwebtoken"; +import {AuthenticatedRequest} from "./authenticated-request.js"; + +function createJwksClient(uri: string): jwksClient.JwksClient { + return jwksClient({ + cache: true, + rateLimit: true, + jwksUri: uri, + }); +} + +const idpConfigs = { + student: { + issuer: getEnvVar(EnvVars.IdpStudentUrl), + jwksClient: createJwksClient(getEnvVar(EnvVars.IdpStudentJwksEndpoint)), + }, + teacher: { + issuer: getEnvVar(EnvVars.IdpTeacherUrl), + jwksClient: createJwksClient(getEnvVar(EnvVars.IdpTeacherJwksEndpoint)), + } +}; + +export const authenticateUser = expressjwt({ + secret: async (_: express.Request, token: jwt.Jwt | undefined) => { + if (!token?.payload || !(token.payload as JwtPayload).iss) { + throw new Error("Invalid token"); + } + + let issuer = (token.payload as JwtPayload).iss; + + let idpConfig = Object.values(idpConfigs).find(config => config.issuer === issuer); + if (!idpConfig) { + throw new Error("Issuer not accepted."); + } + + const signingKey = await idpConfig.jwksClient.getSigningKey(token.header.kid); + if (!signingKey) { + throw new Error("Signing key not found."); + } + return signingKey.getPublicKey(); + }, + audience: getEnvVar(EnvVars.IdpAudience), + algorithms: ["RS256"], + credentialsRequired: false +}); + +const authorizeRole = (studentsAllowed: boolean, teachersAllowed: boolean) => { + return (req: AuthenticatedRequest, res: express.Response, next: express.NextFunction): void => { + if (!req.auth) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + + const issuer = req.auth.iss; + if (issuer === idpConfigs.student.issuer && !studentsAllowed) { + res.status(403).json({ message: "Students not allowed" }); + return; + } + if (issuer === idpConfigs.teacher.issuer && !teachersAllowed) { + res.status(403).json({ message: "Teachers not allowed" }); + return; + } + + next(); // User is allowed + }; +}; + +export const authenticatedOnly = authorizeRole(true, true); +export const studentsOnly = authorizeRole(true, false); +export const teachersOnly = authorizeRole(false, true); diff --git a/backend/src/middleware/auth/authenticated-request.ts b/backend/src/middleware/auth/authenticated-request.ts new file mode 100644 index 00000000..9b33de6f --- /dev/null +++ b/backend/src/middleware/auth/authenticated-request.ts @@ -0,0 +1,6 @@ +import { Request } from "express"; +import { JwtPayload } from "jsonwebtoken"; + +export interface AuthenticatedRequest extends Request { + auth?: JwtPayload; // Optional, as req.auth might be undefined if authentication is optional +} diff --git a/backend/src/routes/student.ts b/backend/src/routes/student.ts index a11c1fbc..f9697478 100644 --- a/backend/src/routes/student.ts +++ b/backend/src/routes/student.ts @@ -41,14 +41,14 @@ router.get('/:id/submissions', (req, res) => { }); }) - + // the list of assignments a student has router.get('/:id/assignments', (req, res) => { res.json({ assignments: [ '0' ], }); }) - + // the list of groups a student is in router.get('/:id/groups', (req, res) => { res.json({ @@ -56,4 +56,4 @@ router.get('/:id/groups', (req, res) => { }); }) -export default router \ No newline at end of file +export default router diff --git a/backend/src/util/envvars.ts b/backend/src/util/envvars.ts index 5a06ac22..2dfcf640 100644 --- a/backend/src/util/envvars.ts +++ b/backend/src/util/envvars.ts @@ -1,5 +1,8 @@ const PREFIX = 'DWENGO_'; const DB_PREFIX = PREFIX + 'DB_'; +const IDP_PREFIX = PREFIX + 'AUTH_'; +const STUDENT_IDP_PREFIX = IDP_PREFIX + 'STUDENT_'; +const TEACHER_IDP_PREFIX = IDP_PREFIX + 'TEACHER_'; type EnvVar = { key: string; required?: boolean; defaultValue?: any }; @@ -11,6 +14,11 @@ export const EnvVars: { [key: string]: EnvVar } = { DbUsername: { key: DB_PREFIX + 'USERNAME', required: true }, DbPassword: { key: DB_PREFIX + 'PASSWORD', required: true }, DbUpdate: { key: DB_PREFIX + 'UPDATE', defaultValue: false }, + IdpStudentUrl: { key: STUDENT_IDP_PREFIX + 'URL', required: true }, + IdpStudentJwksEndpoint: { key: STUDENT_IDP_PREFIX + 'JWKS_ENDPOINT', required: true }, + IdpTeacherUrl: { key: TEACHER_IDP_PREFIX + 'URL', required: true }, + IdpTeacherJwksEndpoint: { key: TEACHER_IDP_PREFIX + 'JWKS_ENDPOINT', required: true }, + IdpAudience: { key: IDP_PREFIX + 'AUDIENCE', defaultValue: 'account' } } as const; /** diff --git a/docker-compose.yml b/docker-compose.yml index c5230d7c..df906ba4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,6 +9,24 @@ services: - "5431:5432" volumes: - postgres_data:/var/lib/postgresql/data - + idp: # Bron: https://medium.com/@fingervinicius/easy-running-keycloak-with-docker-compose-b0d7a4ee2358 + image: quay.io/keycloak/keycloak:latest + environment: + KC_HOSTNAME: localhost + KC_HOSTNAME_PORT: 7080 + KC_HOSTNAME_STRICT_BACKCHANNEL: "true" + KEYCLOAK_ADMIN: admin + KEYCLOAK_ADMIN_PASSWORD: admin + KC_HEALTH_ENABLED: "true" + KC_LOG_LEVEL: info + healthcheck: + test: [ "CMD", "curl", "-f", "http://localhost:7080/health/ready" ] + interval: 15s + timeout: 2s + retries: 15 + command: ["start-dev", "--http-port", "7080", "--https-port", "7443"] + ports: + - "7080:7080" + - "7443:7443" volumes: postgres_data: diff --git a/package-lock.json b/package-lock.json index 8d47c5b5..50b2a6d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,11 +36,13 @@ "@mikro-orm/postgresql": "6.4.6", "@mikro-orm/reflection": "6.4.6", "@mikro-orm/sqlite": "6.4.6", + "@types/js-yaml": "^4.0.9", "dotenv": "^16.4.7", "express": "^5.0.1", - "uuid": "^11.1.0", + "express-jwt": "^8.5.1", "js-yaml": "^4.1.0", - "@types/js-yaml": "^4.0.9", + "jwks-rsa": "^3.1.0", + "uuid": "^11.1.0" }, "devDependencies": { "@mikro-orm/cli": "^6.4.6", @@ -55,8 +57,7 @@ }, "backend/node_modules/@mikro-orm/sqlite": { "version": "6.4.6", - "resolved": "https://registry.npmjs.org/@mikro-orm/sqlite/-/sqlite-6.4.6.tgz", - "integrity": "sha512-BvoLd6qge2N4P2w9yjPP8+Ya5dxxnZrS6W3B2xm0m8BUesWnaCg2pmGXQpzFjrpYMg40mZ+RJWRTPq4M2Nl4lw==", + "license": "MIT", "dependencies": { "@mikro-orm/knex": "6.4.6", "fs-extra": "11.3.0", @@ -72,8 +73,6 @@ }, "backend/node_modules/globals": { "version": "15.15.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", - "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", "dev": true, "license": "MIT", "engines": { @@ -116,8 +115,6 @@ }, "node_modules/@ampproject/remapping": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -130,8 +127,6 @@ }, "node_modules/@ampproject/remapping/node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "license": "MIT", "dependencies": { @@ -141,8 +136,6 @@ }, "node_modules/@antfu/utils": { "version": "0.7.10", - "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz", - "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", "dev": true, "license": "MIT", "funding": { @@ -151,8 +144,6 @@ }, "node_modules/@asamuzakjp/css-color": { "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-2.8.3.tgz", - "integrity": "sha512-GIc76d9UI1hCvOATjZPyHFmE5qhRccp3/zGfMPapK3jBi+yocEzp6BBB0UnfRYP9NP4FANqUZYb0hnfs3TM3hw==", "dev": true, "license": "MIT", "dependencies": { @@ -165,8 +156,6 @@ }, "node_modules/@babel/code-frame": { "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "dev": true, "license": "MIT", "dependencies": { @@ -180,8 +169,6 @@ }, "node_modules/@babel/compat-data": { "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", - "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", "dev": true, "license": "MIT", "engines": { @@ -190,8 +177,6 @@ }, "node_modules/@babel/core": { "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.9.tgz", - "integrity": "sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw==", "dev": true, "license": "MIT", "dependencies": { @@ -221,8 +206,6 @@ }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", "bin": { @@ -231,8 +214,6 @@ }, "node_modules/@babel/generator": { "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.9.tgz", - "integrity": "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==", "dev": true, "license": "MIT", "dependencies": { @@ -248,8 +229,6 @@ }, "node_modules/@babel/generator/node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "license": "MIT", "dependencies": { @@ -259,8 +238,6 @@ }, "node_modules/@babel/helper-annotate-as-pure": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", - "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", "dev": true, "license": "MIT", "dependencies": { @@ -272,8 +249,6 @@ }, "node_modules/@babel/helper-compilation-targets": { "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", - "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", "dev": true, "license": "MIT", "dependencies": { @@ -289,8 +264,6 @@ }, "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "license": "ISC", "dependencies": { @@ -299,8 +272,6 @@ }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", "bin": { @@ -309,8 +280,6 @@ }, "node_modules/@babel/helper-create-class-features-plugin": { "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.26.9.tgz", - "integrity": "sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg==", "dev": true, "license": "MIT", "dependencies": { @@ -331,8 +300,6 @@ }, "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", "bin": { @@ -341,8 +308,6 @@ }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", - "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", "dev": true, "license": "MIT", "dependencies": { @@ -355,8 +320,6 @@ }, "node_modules/@babel/helper-module-imports": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", "dev": true, "license": "MIT", "dependencies": { @@ -369,8 +332,6 @@ }, "node_modules/@babel/helper-module-transforms": { "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", "dev": true, "license": "MIT", "dependencies": { @@ -387,8 +348,6 @@ }, "node_modules/@babel/helper-optimise-call-expression": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", - "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", "dev": true, "license": "MIT", "dependencies": { @@ -400,8 +359,6 @@ }, "node_modules/@babel/helper-plugin-utils": { "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", - "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", "dev": true, "license": "MIT", "engines": { @@ -410,8 +367,6 @@ }, "node_modules/@babel/helper-replace-supers": { "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz", - "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==", "dev": true, "license": "MIT", "dependencies": { @@ -428,8 +383,6 @@ }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", - "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", "dev": true, "license": "MIT", "dependencies": { @@ -442,8 +395,6 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -451,8 +402,6 @@ }, "node_modules/@babel/helper-validator-identifier": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -460,8 +409,6 @@ }, "node_modules/@babel/helper-validator-option": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", "dev": true, "license": "MIT", "engines": { @@ -470,8 +417,6 @@ }, "node_modules/@babel/helpers": { "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.9.tgz", - "integrity": "sha512-Mz/4+y8udxBKdmzt/UjPACs4G3j5SshJJEFFKxlCGPydG4JAHXxjWjAwjd09tf6oINvl1VfMJo+nB7H2YKQ0dA==", "dev": true, "license": "MIT", "dependencies": { @@ -484,8 +429,6 @@ }, "node_modules/@babel/parser": { "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz", - "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==", "license": "MIT", "dependencies": { "@babel/types": "^7.26.9" @@ -499,8 +442,6 @@ }, "node_modules/@babel/plugin-proposal-decorators": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.25.9.tgz", - "integrity": "sha512-smkNLL/O1ezy9Nhy4CNosc4Va+1wo5w4gzSZeLe6y6dM4mmHfYOCPolXQPHQxonZCF+ZyebxN9vqOolkYrSn5g==", "dev": true, "license": "MIT", "dependencies": { @@ -517,8 +458,6 @@ }, "node_modules/@babel/plugin-syntax-decorators": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.25.9.tgz", - "integrity": "sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==", "dev": true, "license": "MIT", "dependencies": { @@ -533,8 +472,6 @@ }, "node_modules/@babel/plugin-syntax-import-attributes": { "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", - "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", "dev": true, "license": "MIT", "dependencies": { @@ -549,8 +486,6 @@ }, "node_modules/@babel/plugin-syntax-import-meta": { "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, "license": "MIT", "dependencies": { @@ -562,8 +497,6 @@ }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", - "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", "dev": true, "license": "MIT", "dependencies": { @@ -578,8 +511,6 @@ }, "node_modules/@babel/plugin-syntax-typescript": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", - "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", "dev": true, "license": "MIT", "dependencies": { @@ -594,8 +525,6 @@ }, "node_modules/@babel/plugin-transform-typescript": { "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.8.tgz", - "integrity": "sha512-bME5J9AC8ChwA7aEPJ6zym3w7aObZULHhbNLU0bKUhKsAkylkzUdq+0kdymh9rzi8nlNFl2bmldFBCKNJBUpuw==", "dev": true, "license": "MIT", "dependencies": { @@ -614,8 +543,6 @@ }, "node_modules/@babel/template": { "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", - "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", "dev": true, "license": "MIT", "dependencies": { @@ -629,8 +556,6 @@ }, "node_modules/@babel/traverse": { "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.9.tgz", - "integrity": "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==", "dev": true, "license": "MIT", "dependencies": { @@ -648,8 +573,6 @@ }, "node_modules/@babel/traverse/node_modules/globals": { "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, "license": "MIT", "engines": { @@ -658,8 +581,6 @@ }, "node_modules/@babel/types": { "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz", - "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.9", @@ -671,8 +592,6 @@ }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "license": "MIT", "dependencies": { @@ -684,8 +603,6 @@ }, "node_modules/@csstools/color-helpers": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.1.tgz", - "integrity": "sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==", "dev": true, "funding": [ { @@ -704,8 +621,6 @@ }, "node_modules/@csstools/css-calc": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.1.tgz", - "integrity": "sha512-rL7kaUnTkL9K+Cvo2pnCieqNpTKgQzy5f+N+5Iuko9HAoasP+xgprVh7KN/MaJVvVL1l0EzQq2MoqBHKSrDrag==", "dev": true, "funding": [ { @@ -728,8 +643,6 @@ }, "node_modules/@csstools/css-color-parser": { "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.7.tgz", - "integrity": "sha512-nkMp2mTICw32uE5NN+EsJ4f5N+IGFeCFu4bGpiKgb2Pq/7J/MpyLBeQ5ry4KKtRFZaYs6sTmcMYrSRIyj5DFKA==", "dev": true, "funding": [ { @@ -756,8 +669,6 @@ }, "node_modules/@csstools/css-parser-algorithms": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", - "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==", "dev": true, "funding": [ { @@ -779,8 +690,6 @@ }, "node_modules/@csstools/css-tokenizer": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz", - "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==", "dev": true, "funding": [ { @@ -797,298 +706,8 @@ "node": ">=18" } }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", - "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz", - "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz", - "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz", - "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz", - "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz", - "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz", - "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz", - "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz", - "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz", - "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz", - "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz", - "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz", - "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz", - "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz", - "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz", - "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, "node_modules/@esbuild/linux-x64": { "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz", - "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==", "cpu": [ "x64" ], @@ -1103,154 +722,8 @@ "node": ">=18" } }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz", - "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz", - "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz", - "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz", - "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz", - "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz", - "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz", - "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz", - "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", "dev": true, "license": "MIT", "dependencies": { @@ -1268,8 +741,6 @@ }, "node_modules/@eslint-community/regexpp": { "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, "license": "MIT", "engines": { @@ -1278,8 +749,6 @@ }, "node_modules/@eslint/compat": { "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.6.tgz", - "integrity": "sha512-k7HNCqApoDHM6XzT30zGoETj+D+uUcZUb+IVAJmar3u6bvHf7hhHJcWx09QHj4/a2qrKZMWU0E16tvkiAdv06Q==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1296,8 +765,6 @@ }, "node_modules/@eslint/config-array": { "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", - "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1311,8 +778,6 @@ }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", "dependencies": { @@ -1322,8 +787,6 @@ }, "node_modules/@eslint/config-array/node_modules/minimatch": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", "dependencies": { @@ -1335,8 +798,6 @@ }, "node_modules/@eslint/core": { "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.11.0.tgz", - "integrity": "sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1348,8 +809,6 @@ }, "node_modules/@eslint/eslintrc": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", - "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", "dev": true, "license": "MIT", "dependencies": { @@ -1372,8 +831,6 @@ }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", "dependencies": { @@ -1383,8 +840,6 @@ }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", "dependencies": { @@ -1396,8 +851,6 @@ }, "node_modules/@eslint/js": { "version": "9.20.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.20.0.tgz", - "integrity": "sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==", "dev": true, "license": "MIT", "engines": { @@ -1406,8 +859,6 @@ }, "node_modules/@eslint/object-schema": { "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1416,8 +867,6 @@ }, "node_modules/@eslint/plugin-kit": { "version": "0.2.6", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.6.tgz", - "integrity": "sha512-+0TjwR1eAUdZtvv/ir1mGX+v0tUoR3VEPB8Up0LLJC+whRW0GgBBtpbOkg/a/U4Dxa6l5a3l9AJ1aWIQVyoWJA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1430,14 +879,11 @@ }, "node_modules/@gar/promisify": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "license": "MIT", "optional": true }, "node_modules/@humanfs/core": { "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1446,8 +892,6 @@ }, "node_modules/@humanfs/node": { "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", - "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1460,8 +904,6 @@ }, "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1474,8 +916,6 @@ }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1488,8 +928,6 @@ }, "node_modules/@humanwhocodes/retry": { "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", - "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1502,8 +940,6 @@ }, "node_modules/@intlify/core-base": { "version": "10.0.5", - "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-10.0.5.tgz", - "integrity": "sha512-F3snDTQs0MdvnnyzTDTVkOYVAZOE/MHwRvF7mn7Jw1yuih4NrFYLNYIymGlLmq4HU2iIdzYsZ7f47bOcwY73XQ==", "license": "MIT", "dependencies": { "@intlify/message-compiler": "10.0.5", @@ -1518,8 +954,6 @@ }, "node_modules/@intlify/message-compiler": { "version": "10.0.5", - "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-10.0.5.tgz", - "integrity": "sha512-6GT1BJ852gZ0gItNZN2krX5QAmea+cmdjMvsWohArAZ3GmHdnNANEcF9JjPXAMRtQ6Ux5E269ymamg/+WU6tQA==", "license": "MIT", "dependencies": { "@intlify/shared": "10.0.5", @@ -1534,8 +968,6 @@ }, "node_modules/@intlify/shared": { "version": "10.0.5", - "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-10.0.5.tgz", - "integrity": "sha512-bmsP4L2HqBF6i6uaMqJMcFBONVjKt+siGluRq4Ca4C0q7W2eMaVZr8iCgF9dKbcVXutftkC7D6z2SaSMmLiDyA==", "license": "MIT", "engines": { "node": ">= 16" @@ -1546,8 +978,6 @@ }, "node_modules/@isaacs/cliui": { "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, "license": "ISC", "dependencies": { @@ -1562,95 +992,8 @@ "node": ">=12" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@jercle/yargonaut": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@jercle/yargonaut/-/yargonaut-1.1.5.tgz", - "integrity": "sha512-zBp2myVvBHp1UaJsNTyS6q4UDKT7eRiqTS4oNTS6VQMd6mpxYOdbeK4pY279cDCdakGy6hG0J3ejoXZVsPwHqw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1661,8 +1004,6 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "dev": true, "license": "MIT", "dependencies": { @@ -1676,8 +1017,6 @@ }, "node_modules/@jridgewell/gen-mapping/node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1687,8 +1026,6 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "license": "MIT", "engines": { @@ -1697,8 +1034,6 @@ }, "node_modules/@jridgewell/set-array": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "license": "MIT", "engines": { @@ -1707,14 +1042,10 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1724,8 +1055,6 @@ }, "node_modules/@mikro-orm/cli": { "version": "6.4.6", - "resolved": "https://registry.npmjs.org/@mikro-orm/cli/-/cli-6.4.6.tgz", - "integrity": "sha512-sTMoDSJrnHZBT+ZAG40OeZwR9zRTYHtaaub9OoMM2CrxfI1KeiNqL/XFB4LaM5SVRAbnoEFpMJwQ8KS+5NcN9w==", "dev": true, "license": "MIT", "dependencies": { @@ -1746,8 +1075,6 @@ }, "node_modules/@mikro-orm/core": { "version": "6.4.6", - "resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-6.4.6.tgz", - "integrity": "sha512-xVm/ALG/3vTMgh6SrvojJ6jjMa0s2hNzWN0triDB16BaNdLwWE4aAaAe+3CuoMFqJAArSOUISTEjExbzELB1ZA==", "license": "MIT", "dependencies": { "dataloader": "2.2.3", @@ -1767,8 +1094,6 @@ }, "node_modules/@mikro-orm/knex": { "version": "6.4.6", - "resolved": "https://registry.npmjs.org/@mikro-orm/knex/-/knex-6.4.6.tgz", - "integrity": "sha512-o6t67tFH/GuPZCCEtKbTTL8HDXNgB2ITjButCTZLwteL0qI9yE/f7K6K+dEUKW+hAL3KRvc2BQeumvCVWFeISg==", "license": "MIT", "dependencies": { "fs-extra": "11.3.0", @@ -1798,8 +1123,6 @@ }, "node_modules/@mikro-orm/postgresql": { "version": "6.4.6", - "resolved": "https://registry.npmjs.org/@mikro-orm/postgresql/-/postgresql-6.4.6.tgz", - "integrity": "sha512-ZcuGp6n/SPzkHPANksjdLPyeu6jT7WCg3ueNViVrxdsguCi+/grz4I+hbOQDXV8uNHCAUOw6+WP2ndcVEYkZZQ==", "license": "MIT", "dependencies": { "@mikro-orm/knex": "6.4.6", @@ -1817,8 +1140,6 @@ }, "node_modules/@mikro-orm/reflection": { "version": "6.4.6", - "resolved": "https://registry.npmjs.org/@mikro-orm/reflection/-/reflection-6.4.6.tgz", - "integrity": "sha512-7mL7HFVnaOOhDNgLjjndWyeJUtOl2wKn0spSqB8uRjS4XtwNEGVZNkW5YD1t/x7TJ99wUhe+oRDiySciiJSeBQ==", "license": "MIT", "dependencies": { "globby": "11.1.0", @@ -1833,8 +1154,6 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -1846,8 +1165,6 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "license": "MIT", "engines": { "node": ">= 8" @@ -1855,8 +1172,6 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -1868,8 +1183,7 @@ }, "node_modules/@npmcli/fs": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "license": "ISC", "optional": true, "dependencies": { "@gar/promisify": "^1.0.1", @@ -1878,9 +1192,7 @@ }, "node_modules/@npmcli/move-file": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", - "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "deprecated": "This functionality has been moved to @npmcli/fs", + "license": "MIT", "optional": true, "dependencies": { "mkdirp": "^1.0.4", @@ -1892,15 +1204,11 @@ }, "node_modules/@one-ini/wasm": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", - "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", "dev": true, "license": "MIT" }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, "license": "MIT", "optional": true, @@ -1910,8 +1218,6 @@ }, "node_modules/@pkgr/core": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", "dev": true, "license": "MIT", "engines": { @@ -1923,8 +1229,6 @@ }, "node_modules/@playwright/test": { "version": "1.50.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.50.1.tgz", - "integrity": "sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1939,15 +1243,11 @@ }, "node_modules/@polka/url": { "version": "1.0.0-next.28", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", - "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", "dev": true, "license": "MIT" }, "node_modules/@rollup/pluginutils": { "version": "5.1.4", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", - "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1967,17 +1267,8 @@ } } }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT" - }, "node_modules/@rollup/pluginutils/node_modules/picomatch": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, "license": "MIT", "engines": { @@ -1987,206 +1278,8 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz", - "integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz", - "integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz", - "integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz", - "integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz", - "integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz", - "integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz", - "integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz", - "integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz", - "integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz", - "integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz", - "integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz", - "integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz", - "integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz", - "integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz", - "integrity": "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==", "cpu": [ "x64" ], @@ -2199,8 +1292,6 @@ }, "node_modules/@rollup/rollup-linux-x64-musl": { "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz", - "integrity": "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==", "cpu": [ "x64" ], @@ -2211,59 +1302,13 @@ "linux" ] }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz", - "integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz", - "integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz", - "integrity": "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@sec-ant/readable-stream": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", - "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", "dev": true, "license": "MIT" }, "node_modules/@sindresorhus/merge-streams": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", - "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", "dev": true, "license": "MIT", "engines": { @@ -2275,8 +1320,7 @@ }, "node_modules/@tootallnate/once": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "license": "MIT", "optional": true, "engines": { "node": ">= 6" @@ -2284,8 +1328,6 @@ }, "node_modules/@ts-morph/common": { "version": "0.26.1", - "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.26.1.tgz", - "integrity": "sha512-Sn28TGl/4cFpcM+jwsH1wLncYq3FtN/BIpem+HOygfBWPT5pAeS5dB4VFVzV8FbnOKHpDLZmvAl4AjPEev5idA==", "license": "MIT", "dependencies": { "fast-glob": "^3.3.2", @@ -2295,44 +1337,31 @@ }, "node_modules/@tsconfig/node10": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node22": { "version": "22.0.0", - "resolved": "https://registry.npmjs.org/@tsconfig/node22/-/node22-22.0.0.tgz", - "integrity": "sha512-twLQ77zevtxobBOD4ToAtVmuYrpeYUh3qh+TEp+08IWhpsrIflVHqQ1F1CiPxQGL7doCdBIOOCF+1Tm833faNg==", "dev": true, "license": "MIT" }, "node_modules/@types/body-parser": { "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, "license": "MIT", "dependencies": { "@types/connect": "*", @@ -2341,9 +1370,6 @@ }, "node_modules/@types/connect": { "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -2351,22 +1377,16 @@ }, "node_modules/@types/eslint-config-prettier": { "version": "6.11.3", - "resolved": "https://registry.npmjs.org/@types/eslint-config-prettier/-/eslint-config-prettier-6.11.3.tgz", - "integrity": "sha512-3wXCiM8croUnhg9LdtZUJQwNcQYGWxxdOWDjPe1ykCqJFPVpzAKfs/2dgSoCtAvdPeaponcWPI7mPcGGp9dkKQ==", "dev": true, "license": "MIT" }, "node_modules/@types/estree": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "dev": true, "license": "MIT" }, "node_modules/@types/express": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.0.tgz", - "integrity": "sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2378,8 +1398,6 @@ }, "node_modules/@types/express-serve-static-core": { "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz", - "integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==", "dev": true, "license": "MIT", "dependencies": { @@ -2391,21 +1409,14 @@ }, "node_modules/@types/http-errors": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true, "license": "MIT" }, "node_modules/@types/js-yaml": { "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", - "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", "license": "MIT" }, "node_modules/@types/jsdom": { "version": "21.1.7", - "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.7.tgz", - "integrity": "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==", "dev": true, "license": "MIT", "dependencies": { @@ -2416,23 +1427,31 @@ }, "node_modules/@types/json-schema": { "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, "license": "MIT" }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.9.tgz", + "integrity": "sha512-uoe+GxEuHbvy12OUQct2X9JenKM3qAscquYymuQN4fMWG9DBQtykrQEFcAbVACF7qaLw9BePSodUL0kquqBJpQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, "node_modules/@types/mime": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", "license": "MIT" }, "node_modules/@types/node": { "version": "22.13.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.4.tgz", - "integrity": "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.20.0" @@ -2440,23 +1459,14 @@ }, "node_modules/@types/qs": { "version": "6.9.18", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", - "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", - "dev": true, "license": "MIT" }, "node_modules/@types/range-parser": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true, "license": "MIT" }, "node_modules/@types/send": { "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, "license": "MIT", "dependencies": { "@types/mime": "^1", @@ -2465,9 +1475,6 @@ }, "node_modules/@types/serve-static": { "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", - "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", - "dev": true, "license": "MIT", "dependencies": { "@types/http-errors": "*", @@ -2477,15 +1484,11 @@ }, "node_modules/@types/tough-cookie": { "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", - "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", "dev": true, "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.24.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.1.tgz", - "integrity": "sha512-ll1StnKtBigWIGqvYDVuDmXJHVH4zLVot1yQ4fJtLpL7qacwkxJc1T0bptqw+miBQ/QfUbhl1TcQ4accW5KUyA==", "dev": true, "license": "MIT", "dependencies": { @@ -2514,8 +1517,6 @@ }, "node_modules/@typescript-eslint/parser": { "version": "8.24.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.24.1.tgz", - "integrity": "sha512-Tqoa05bu+t5s8CTZFaGpCH2ub3QeT9YDkXbPd3uQ4SfsLoh1/vv2GEYAioPoxCWJJNsenXlC88tRjwoHNts1oQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2539,8 +1540,6 @@ }, "node_modules/@typescript-eslint/scope-manager": { "version": "8.24.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.24.1.tgz", - "integrity": "sha512-OdQr6BNBzwRjNEXMQyaGyZzgg7wzjYKfX2ZBV3E04hUCBDv3GQCHiz9RpqdUIiVrMgJGkXm3tcEh4vFSHreS2Q==", "dev": true, "license": "MIT", "dependencies": { @@ -2557,8 +1556,6 @@ }, "node_modules/@typescript-eslint/type-utils": { "version": "8.24.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.24.1.tgz", - "integrity": "sha512-/Do9fmNgCsQ+K4rCz0STI7lYB4phTtEXqqCAs3gZW0pnK7lWNkvWd5iW545GSmApm4AzmQXmSqXPO565B4WVrw==", "dev": true, "license": "MIT", "dependencies": { @@ -2581,8 +1578,6 @@ }, "node_modules/@typescript-eslint/types": { "version": "8.24.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.24.1.tgz", - "integrity": "sha512-9kqJ+2DkUXiuhoiYIUvIYjGcwle8pcPpdlfkemGvTObzgmYfJ5d0Qm6jwb4NBXP9W1I5tss0VIAnWFumz3mC5A==", "dev": true, "license": "MIT", "engines": { @@ -2595,8 +1590,6 @@ }, "node_modules/@typescript-eslint/typescript-estree": { "version": "8.24.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.1.tgz", - "integrity": "sha512-UPyy4MJ/0RE648DSKQe9g0VDSehPINiejjA6ElqnFaFIhI6ZEiZAkUI0D5MCk0bQcTf/LVqZStvQ6K4lPn/BRg==", "dev": true, "license": "MIT", "dependencies": { @@ -2622,8 +1615,6 @@ }, "node_modules/@typescript-eslint/utils": { "version": "8.24.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.24.1.tgz", - "integrity": "sha512-OOcg3PMMQx9EXspId5iktsI3eMaXVwlhC8BvNnX6B5w9a4dVgpkQZuU8Hy67TolKcl+iFWq0XX+jbDGN4xWxjQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2646,8 +1637,6 @@ }, "node_modules/@typescript-eslint/visitor-keys": { "version": "8.24.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.1.tgz", - "integrity": "sha512-EwVHlp5l+2vp8CoqJm9KikPZgi3gbdZAtabKT9KPShGeOcJhsv4Zdo3oc8T8I0uKEmYoU4ItyxbptjF08enaxg==", "dev": true, "license": "MIT", "dependencies": { @@ -2664,8 +1653,6 @@ }, "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -2677,8 +1664,6 @@ }, "node_modules/@vitejs/plugin-vue": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.1.tgz", - "integrity": "sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==", "dev": true, "license": "MIT", "engines": { @@ -2691,8 +1676,6 @@ }, "node_modules/@vitest/eslint-plugin": { "version": "1.1.31", - "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.1.31.tgz", - "integrity": "sha512-xlsLr+e+AXZ/00eVZCtNmMeCJoJaRCoLDiAgLcxgQjSS1EertieB2MUHf8xIqPKs9lECc/UpL+y1xDcpvi02hw==", "dev": true, "license": "MIT", "peerDependencies": { @@ -2712,8 +1695,6 @@ }, "node_modules/@vitest/expect": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.6.tgz", - "integrity": "sha512-zBduHf/ja7/QRX4HdP1DSq5XrPgdN+jzLOwaTq/0qZjYfgETNFCKf9nOAp2j3hmom3oTbczuUzrzg9Hafh7hNg==", "dev": true, "license": "MIT", "dependencies": { @@ -2728,8 +1709,6 @@ }, "node_modules/@vitest/mocker": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.6.tgz", - "integrity": "sha512-KPztr4/tn7qDGZfqlSPQoF2VgJcKxnDNhmfR3VgZ6Fy1bO8T9Fc1stUiTXtqz0yG24VpD00pZP5f8EOFknjNuQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2753,10 +1732,16 @@ } } }, + "node_modules/@vitest/mocker/node_modules/estree-walker": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/@vitest/pretty-format": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.6.tgz", - "integrity": "sha512-Zyctv3dbNL+67qtHfRnUE/k8qxduOamRfAL1BurEIQSyOEFffoMvx2pnDSSbKAAVxY0Ej2J/GH2dQKI0W2JyVg==", "dev": true, "license": "MIT", "dependencies": { @@ -2768,8 +1753,6 @@ }, "node_modules/@vitest/runner": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.6.tgz", - "integrity": "sha512-JopP4m/jGoaG1+CBqubV/5VMbi7L+NQCJTu1J1Pf6YaUbk7bZtaq5CX7p+8sY64Sjn1UQ1XJparHfcvTTdu9cA==", "dev": true, "license": "MIT", "dependencies": { @@ -2782,8 +1765,6 @@ }, "node_modules/@vitest/snapshot": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.6.tgz", - "integrity": "sha512-qKSmxNQwT60kNwwJHMVwavvZsMGXWmngD023OHSgn873pV0lylK7dwBTfYP7e4URy5NiBCHHiQGA9DHkYkqRqg==", "dev": true, "license": "MIT", "dependencies": { @@ -2797,8 +1778,6 @@ }, "node_modules/@vitest/spy": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.6.tgz", - "integrity": "sha512-HfOGx/bXtjy24fDlTOpgiAEJbRfFxoX3zIGagCqACkFKKZ/TTOE6gYMKXlqecvxEndKFuNHcHqP081ggZ2yM0Q==", "dev": true, "license": "MIT", "dependencies": { @@ -2810,8 +1789,6 @@ }, "node_modules/@vitest/utils": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.6.tgz", - "integrity": "sha512-18ktZpf4GQFTbf9jK543uspU03Q2qya7ZGya5yiZ0Gx0nnnalBvd5ZBislbl2EhLjM8A8rt4OilqKG7QwcGkvQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2825,8 +1802,6 @@ }, "node_modules/@volar/language-core": { "version": "2.4.11", - "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.11.tgz", - "integrity": "sha512-lN2C1+ByfW9/JRPpqScuZt/4OrUUse57GLI6TbLgTIqBVemdl1wNcZ1qYGEo2+Gw8coYLgCy7SuKqn6IrQcQgg==", "dev": true, "license": "MIT", "dependencies": { @@ -2835,15 +1810,11 @@ }, "node_modules/@volar/source-map": { "version": "2.4.11", - "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.11.tgz", - "integrity": "sha512-ZQpmafIGvaZMn/8iuvCFGrW3smeqkq/IIh9F1SdSx9aUl0J4Iurzd6/FhmjNO5g2ejF3rT45dKskgXWiofqlZQ==", "dev": true, "license": "MIT" }, "node_modules/@volar/typescript": { "version": "2.4.11", - "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.11.tgz", - "integrity": "sha512-2DT+Tdh88Spp5PyPbqhyoYavYCPDsqbHLFwcUI9K1NlY1YgUJvujGdrqUp0zWxnW7KWNTr3xSpMuv2WnaTKDAw==", "dev": true, "license": "MIT", "dependencies": { @@ -2854,15 +1825,11 @@ }, "node_modules/@vue/babel-helper-vue-transform-on": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.2.5.tgz", - "integrity": "sha512-lOz4t39ZdmU4DJAa2hwPYmKc8EsuGa2U0L9KaZaOJUt0UwQNjNA3AZTq6uEivhOKhhG1Wvy96SvYBoFmCg3uuw==", "dev": true, "license": "MIT" }, "node_modules/@vue/babel-plugin-jsx": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.2.5.tgz", - "integrity": "sha512-zTrNmOd4939H9KsRIGmmzn3q2zvv1mjxkYZHgqHZgDrXz5B1Q3WyGEjO2f+JrmKghvl1JIRcvo63LgM1kH5zFg==", "dev": true, "license": "MIT", "dependencies": { @@ -2888,8 +1855,6 @@ }, "node_modules/@vue/babel-plugin-resolve-type": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.2.5.tgz", - "integrity": "sha512-U/ibkQrf5sx0XXRnUZD1mo5F7PkpKyTbfXM3a3rC4YnUz6crHEz9Jg09jzzL6QYlXNto/9CePdOg/c87O4Nlfg==", "dev": true, "license": "MIT", "dependencies": { @@ -2905,8 +1870,6 @@ }, "node_modules/@vue/compiler-core": { "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz", - "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", "license": "MIT", "dependencies": { "@babel/parser": "^7.25.3", @@ -2916,16 +1879,8 @@ "source-map-js": "^1.2.0" } }, - "node_modules/@vue/compiler-core/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "license": "MIT" - }, "node_modules/@vue/compiler-dom": { "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz", - "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", "license": "MIT", "dependencies": { "@vue/compiler-core": "3.5.13", @@ -2934,8 +1889,6 @@ }, "node_modules/@vue/compiler-sfc": { "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz", - "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==", "license": "MIT", "dependencies": { "@babel/parser": "^7.25.3", @@ -2949,16 +1902,8 @@ "source-map-js": "^1.2.0" } }, - "node_modules/@vue/compiler-sfc/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "license": "MIT" - }, "node_modules/@vue/compiler-ssr": { "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz", - "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==", "license": "MIT", "dependencies": { "@vue/compiler-dom": "3.5.13", @@ -2967,8 +1912,6 @@ }, "node_modules/@vue/compiler-vue2": { "version": "2.7.16", - "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", - "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", "dev": true, "license": "MIT", "dependencies": { @@ -2978,14 +1921,10 @@ }, "node_modules/@vue/devtools-api": { "version": "6.6.4", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", - "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", "license": "MIT" }, "node_modules/@vue/devtools-core": { "version": "7.7.2", - "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-7.7.2.tgz", - "integrity": "sha512-lexREWj1lKi91Tblr38ntSsy6CvI8ba7u+jmwh2yruib/ltLUcsIzEjCnrkh1yYGGIKXbAuYV2tOG10fGDB9OQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3002,8 +1941,6 @@ }, "node_modules/@vue/devtools-core/node_modules/nanoid": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.0.tgz", - "integrity": "sha512-zDAl/llz8Ue/EblwSYwdxGBYfj46IM1dhjVi8dyp9LQffoIGxJEAHj2oeZ4uNcgycSRcQ83CnfcZqEJzVDLcDw==", "dev": true, "funding": [ { @@ -3021,8 +1958,6 @@ }, "node_modules/@vue/devtools-kit": { "version": "7.7.2", - "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.2.tgz", - "integrity": "sha512-CY0I1JH3Z8PECbn6k3TqM1Bk9ASWxeMtTCvZr7vb+CHi+X/QwQm5F1/fPagraamKMAHVfuuCbdcnNg1A4CYVWQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3037,8 +1972,6 @@ }, "node_modules/@vue/devtools-shared": { "version": "7.7.2", - "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.2.tgz", - "integrity": "sha512-uBFxnp8gwW2vD6FrJB8JZLUzVb6PNRG0B0jBnHsOH8uKyva2qINY8PTF5Te4QlTbMDqU5K6qtJDr6cNsKWhbOA==", "dev": true, "license": "MIT", "dependencies": { @@ -3047,8 +1980,6 @@ }, "node_modules/@vue/eslint-config-prettier": { "version": "10.2.0", - "resolved": "https://registry.npmjs.org/@vue/eslint-config-prettier/-/eslint-config-prettier-10.2.0.tgz", - "integrity": "sha512-GL3YBLwv/+b86yHcNNfPJxOTtVFJ4Mbc9UU3zR+KVoG7SwGTjPT+32fXamscNumElhcpXW3mT0DgzS9w32S7Bw==", "dev": true, "license": "MIT", "dependencies": { @@ -3062,8 +1993,6 @@ }, "node_modules/@vue/eslint-config-typescript": { "version": "14.4.0", - "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-14.4.0.tgz", - "integrity": "sha512-daU+eAekEeVz3CReE4PRW25fe+OJDKwE28jHN6LimDEnuFMbJ6H4WGogEpNof276wVP6UvzOeJQfLFjB5mW29A==", "dev": true, "license": "MIT", "dependencies": { @@ -3088,8 +2017,6 @@ }, "node_modules/@vue/language-core": { "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.2.tgz", - "integrity": "sha512-QotO41kurE5PLf3vrNgGTk3QswO2PdUFjBwNiOi7zMmGhwb25PSTh9hD1MCgKC06AVv+8sZQvlL3Do4TTVHSiQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3113,8 +2040,6 @@ }, "node_modules/@vue/reactivity": { "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz", - "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==", "license": "MIT", "dependencies": { "@vue/shared": "3.5.13" @@ -3122,8 +2047,6 @@ }, "node_modules/@vue/runtime-core": { "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.13.tgz", - "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==", "license": "MIT", "dependencies": { "@vue/reactivity": "3.5.13", @@ -3132,8 +2055,6 @@ }, "node_modules/@vue/runtime-dom": { "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz", - "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==", "license": "MIT", "dependencies": { "@vue/reactivity": "3.5.13", @@ -3144,8 +2065,6 @@ }, "node_modules/@vue/server-renderer": { "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.13.tgz", - "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==", "license": "MIT", "dependencies": { "@vue/compiler-ssr": "3.5.13", @@ -3157,14 +2076,10 @@ }, "node_modules/@vue/shared": { "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz", - "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==", "license": "MIT" }, "node_modules/@vue/test-utils": { "version": "2.4.6", - "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.6.tgz", - "integrity": "sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==", "dev": true, "license": "MIT", "dependencies": { @@ -3174,8 +2089,6 @@ }, "node_modules/@vue/tsconfig": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.7.0.tgz", - "integrity": "sha512-ku2uNz5MaZ9IerPPUyOHzyjhXoX2kVJaVf7hL315DC17vS6IiZRmmCPfggNbU16QTvM80+uYYy3eYJB59WCtvg==", "dev": true, "license": "MIT", "peerDependencies": { @@ -3193,8 +2106,6 @@ }, "node_modules/abbrev": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.0.tgz", - "integrity": "sha512-+/kfrslGQ7TNV2ecmQwMJj/B65g5KVq1/L3SGVZ3tCYGqlzFuFCGBZJtMP99wH3NpEUyAjn0zPdPUg0D+DwrOA==", "dev": true, "license": "ISC", "engines": { @@ -3203,8 +2114,6 @@ }, "node_modules/accepts": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", "dependencies": { "mime-types": "^3.0.0", @@ -3216,8 +2125,6 @@ }, "node_modules/acorn": { "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, "license": "MIT", "bin": { @@ -3229,8 +2136,6 @@ }, "node_modules/acorn-jsx": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -3239,8 +2144,6 @@ }, "node_modules/acorn-walk": { "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", "dev": true, "license": "MIT", "dependencies": { @@ -3252,8 +2155,6 @@ }, "node_modules/agent-base": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", "dev": true, "license": "MIT", "engines": { @@ -3262,8 +2163,7 @@ }, "node_modules/agentkeepalive": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", - "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", "optional": true, "dependencies": { "humanize-ms": "^1.2.1" @@ -3274,8 +2174,7 @@ }, "node_modules/aggregate-error": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "license": "MIT", "optional": true, "dependencies": { "clean-stack": "^2.0.0", @@ -3287,8 +2186,6 @@ }, "node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", "dependencies": { @@ -3303,26 +2200,23 @@ } }, "node_modules/alien-signals": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-1.0.4.tgz", - "integrity": "sha512-DJqqQD3XcsaQcQ1s+iE2jDUZmmQpXwHiR6fCAim/w87luaW+vmLY8fMlrdkmRwzaFXhkxf3rqPCR59tKVv1MDw==", + "version": "1.0.3", "dev": true, "license": "MIT" }, "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "version": "6.1.0", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -3337,15 +2231,12 @@ }, "node_modules/aproba": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "license": "ISC", "optional": true }, "node_modules/are-we-there-yet": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "deprecated": "This package is no longer supported.", + "license": "ISC", "optional": true, "dependencies": { "delegates": "^1.0.0", @@ -3357,21 +2248,15 @@ }, "node_modules/arg": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true, "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "license": "Python-2.0" }, "node_modules/array-union": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "license": "MIT", "engines": { "node": ">=8" @@ -3379,8 +2264,6 @@ }, "node_modules/assertion-error": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, "license": "MIT", "engines": { @@ -3389,21 +2272,15 @@ }, "node_modules/asynckit": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true, "license": "MIT" }, "node_modules/balanced-match": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { "type": "github", @@ -3417,20 +2294,18 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/bindings": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", "dependencies": { "file-uri-to-path": "1.0.0" } }, "node_modules/birpc": { "version": "0.2.19", - "resolved": "https://registry.npmjs.org/birpc/-/birpc-0.2.19.tgz", - "integrity": "sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ==", "dev": true, "license": "MIT", "funding": { @@ -3439,8 +2314,7 @@ }, "node_modules/bl": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -3449,8 +2323,6 @@ }, "node_modules/body-parser": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.1.0.tgz", - "integrity": "sha512-/hPxh61E+ll0Ujp24Ilm64cykicul1ypfwjVttduAiEdtnJFvLePSrIPk+HMImtNv5270wOGCb1Tns2rybMkoQ==", "license": "MIT", "dependencies": { "bytes": "^3.1.2", @@ -3469,8 +2341,6 @@ }, "node_modules/body-parser/node_modules/qs": { "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -3484,15 +2354,11 @@ }, "node_modules/boolbase": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true, "license": "ISC" }, "node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -3500,8 +2366,6 @@ }, "node_modules/braces": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -3512,8 +2376,6 @@ }, "node_modules/browserslist": { "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", "dev": true, "funding": [ { @@ -3545,8 +2407,6 @@ }, "node_modules/buffer": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "funding": [ { "type": "github", @@ -3561,15 +2421,20 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, "node_modules/bundle-name": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", - "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", "dev": true, "license": "MIT", "dependencies": { @@ -3584,8 +2449,6 @@ }, "node_modules/bytes": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -3593,8 +2456,6 @@ }, "node_modules/cac": { "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true, "license": "MIT", "engines": { @@ -3603,8 +2464,7 @@ }, "node_modules/cacache": { "version": "15.3.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "license": "ISC", "optional": true, "dependencies": { "@npmcli/fs": "^1.0.0", @@ -3632,8 +2492,7 @@ }, "node_modules/cacache/node_modules/brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", "optional": true, "dependencies": { "balanced-match": "^1.0.0", @@ -3642,9 +2501,7 @@ }, "node_modules/cacache/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", "optional": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -3663,8 +2520,7 @@ }, "node_modules/cacache/node_modules/lru-cache": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", "optional": true, "dependencies": { "yallist": "^4.0.0" @@ -3675,8 +2531,7 @@ }, "node_modules/cacache/node_modules/minimatch": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", "optional": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -3687,8 +2542,7 @@ }, "node_modules/cacache/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "optional": true, "dependencies": { "yallist": "^4.0.0" @@ -3699,14 +2553,11 @@ }, "node_modules/cacache/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC", "optional": true }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -3718,8 +2569,6 @@ }, "node_modules/call-bound": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -3734,8 +2583,6 @@ }, "node_modules/callsites": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, "license": "MIT", "engines": { @@ -3744,8 +2591,6 @@ }, "node_modules/caniuse-lite": { "version": "1.0.30001700", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001700.tgz", - "integrity": "sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==", "dev": true, "funding": [ { @@ -3765,8 +2610,6 @@ }, "node_modules/chai": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", - "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", "dev": true, "license": "MIT", "dependencies": { @@ -3782,8 +2625,6 @@ }, "node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -3799,8 +2640,6 @@ }, "node_modules/check-error": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", - "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", "dev": true, "license": "MIT", "engines": { @@ -3809,16 +2648,14 @@ }, "node_modules/chownr": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/clean-stack": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "license": "MIT", "optional": true, "engines": { "node": ">=6" @@ -3826,8 +2663,6 @@ }, "node_modules/cliui": { "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "license": "ISC", "dependencies": { @@ -3839,16 +2674,65 @@ "node": ">=12" } }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/code-block-writer": { "version": "13.0.3", - "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", - "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", "license": "MIT" }, "node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3860,15 +2744,12 @@ }, "node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, "license": "MIT" }, "node_modules/color-support": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", "optional": true, "bin": { "color-support": "bin.js" @@ -3876,14 +2757,10 @@ }, "node_modules/colorette": { "version": "2.0.19", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", - "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", "license": "MIT" }, "node_modules/combined-stream": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "license": "MIT", "dependencies": { @@ -3895,8 +2772,6 @@ }, "node_modules/commander": { "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "license": "MIT", "engines": { "node": ">=14" @@ -3904,15 +2779,11 @@ }, "node_modules/concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "devOptional": true, "license": "MIT" }, "node_modules/config-chain": { "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3922,14 +2793,11 @@ }, "node_modules/console-control-strings": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC", "optional": true }, "node_modules/content-disposition": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" @@ -3940,8 +2808,6 @@ }, "node_modules/content-type": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -3949,15 +2815,11 @@ }, "node_modules/convert-source-map": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, "license": "MIT" }, "node_modules/cookie": { "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -3965,8 +2827,6 @@ }, "node_modules/cookie-signature": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "license": "MIT", "engines": { "node": ">=6.6.0" @@ -3974,8 +2834,6 @@ }, "node_modules/copy-anything": { "version": "3.0.5", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", - "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", "dev": true, "license": "MIT", "dependencies": { @@ -3990,15 +2848,11 @@ }, "node_modules/create-require": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true, "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { @@ -4012,8 +2866,6 @@ }, "node_modules/cssesc": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, "license": "MIT", "bin": { @@ -4025,8 +2877,6 @@ }, "node_modules/cssstyle": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.2.1.tgz", - "integrity": "sha512-9+vem03dMXG7gDmZ62uqmRiMRNtinIZ9ZyuF6BdxzfOD+FdN5hretzynkn0ReS2DO2GSw76RWHs0UmJPI2zUjw==", "dev": true, "license": "MIT", "dependencies": { @@ -4039,14 +2889,10 @@ }, "node_modules/csstype": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "license": "MIT" }, "node_modules/data-urls": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", - "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", "dev": true, "license": "MIT", "dependencies": { @@ -4059,21 +2905,15 @@ }, "node_modules/dataloader": { "version": "2.2.3", - "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.3.tgz", - "integrity": "sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==", "license": "MIT" }, "node_modules/de-indent": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", - "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", "dev": true, "license": "MIT" }, "node_modules/debug": { "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -4089,15 +2929,12 @@ }, "node_modules/decimal.js": { "version": "10.5.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", - "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", "dev": true, "license": "MIT" }, "node_modules/decompress-response": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", "dependencies": { "mimic-response": "^3.1.0" }, @@ -4110,8 +2947,6 @@ }, "node_modules/deep-eql": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", - "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", "dev": true, "license": "MIT", "engines": { @@ -4120,23 +2955,18 @@ }, "node_modules/deep-extend": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", "engines": { "node": ">=4.0.0" } }, "node_modules/deep-is": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, "license": "MIT" }, "node_modules/default-browser": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", - "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", "dev": true, "license": "MIT", "dependencies": { @@ -4152,8 +2982,6 @@ }, "node_modules/default-browser-id": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", - "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", "dev": true, "license": "MIT", "engines": { @@ -4165,8 +2993,6 @@ }, "node_modules/define-lazy-prop": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "dev": true, "license": "MIT", "engines": { @@ -4178,8 +3004,6 @@ }, "node_modules/delayed-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, "license": "MIT", "engines": { @@ -4188,14 +3012,11 @@ }, "node_modules/delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT", "optional": true }, "node_modules/depd": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -4203,8 +3024,6 @@ }, "node_modules/destroy": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "license": "MIT", "engines": { "node": ">= 0.8", @@ -4213,16 +3032,13 @@ }, "node_modules/detect-libc": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "license": "Apache-2.0", "engines": { "node": ">=8" } }, "node_modules/diff": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -4231,8 +3047,6 @@ }, "node_modules/dir-glob": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "license": "MIT", "dependencies": { "path-type": "^4.0.0" @@ -4243,8 +3057,6 @@ }, "node_modules/dotenv": { "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -4255,8 +3067,6 @@ }, "node_modules/dunder-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -4277,15 +3087,20 @@ }, "node_modules/eastasianwidth": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true, "license": "MIT" }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/editorconfig": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", - "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", "dev": true, "license": "MIT", "dependencies": { @@ -4303,8 +3118,6 @@ }, "node_modules/editorconfig/node_modules/minimatch": { "version": "9.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", - "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", "dev": true, "license": "ISC", "dependencies": { @@ -4319,28 +3132,20 @@ }, "node_modules/ee-first": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "license": "MIT" }, "node_modules/electron-to-chromium": { "version": "1.5.102", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.102.tgz", - "integrity": "sha512-eHhqaja8tE/FNpIiBrvBjFV/SSKpyWHLvxuR9dPTdo+3V9ppdLmFB7ZZQ98qNovcngPLYIz0oOBF9P0FfZef5Q==", "dev": true, "license": "ISC" }, "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "version": "9.2.2", "dev": true, "license": "MIT" }, "node_modules/encodeurl": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -4348,8 +3153,7 @@ }, "node_modules/encoding": { "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "license": "MIT", "optional": true, "dependencies": { "iconv-lite": "^0.6.2" @@ -4357,8 +3161,7 @@ }, "node_modules/encoding/node_modules/iconv-lite": { "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -4369,16 +3172,13 @@ }, "node_modules/end-of-stream": { "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "license": "MIT", "dependencies": { "once": "^1.4.0" } }, "node_modules/entities": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -4389,8 +3189,7 @@ }, "node_modules/env-paths": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", "optional": true, "engines": { "node": ">=6" @@ -4398,14 +3197,11 @@ }, "node_modules/err-code": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "license": "MIT", "optional": true }, "node_modules/error-stack-parser-es": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-0.1.5.tgz", - "integrity": "sha512-xHku1X40RO+fO8yJ8Wh2f2rZWVjqyhb1zgq1yZ8aZRQkv6OOKhKWRUaht3eSCUbAOBaKIgM+ykwFLE+QUxgGeg==", "dev": true, "license": "MIT", "funding": { @@ -4414,8 +3210,6 @@ }, "node_modules/es-define-property": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -4423,8 +3217,6 @@ }, "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==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -4432,15 +3224,11 @@ }, "node_modules/es-module-lexer": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", - "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", "dev": true, "license": "MIT" }, "node_modules/es-object-atoms": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -4451,8 +3239,6 @@ }, "node_modules/es-set-tostringtag": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dev": true, "license": "MIT", "dependencies": { @@ -4467,8 +3253,6 @@ }, "node_modules/esbuild": { "version": "0.25.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", - "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4508,8 +3292,6 @@ }, "node_modules/escalade": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "license": "MIT", "engines": { "node": ">=6" @@ -4517,14 +3299,10 @@ }, "node_modules/escape-html": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "license": "MIT" }, "node_modules/escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "license": "MIT", "engines": { @@ -4536,8 +3314,6 @@ }, "node_modules/eslint": { "version": "9.20.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.20.1.tgz", - "integrity": "sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g==", "dev": true, "license": "MIT", "dependencies": { @@ -4596,8 +3372,6 @@ }, "node_modules/eslint-config-prettier": { "version": "10.0.1", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.0.1.tgz", - "integrity": "sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw==", "dev": true, "license": "MIT", "bin": { @@ -4609,8 +3383,6 @@ }, "node_modules/eslint-plugin-playwright": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-2.2.0.tgz", - "integrity": "sha512-qSQpAw7RcSzE3zPp8FMGkthaCWovHZ/BsXtpmnGax9vQLIovlh1bsZHEa2+j2lv9DWhnyeLM/qZmp7ffQZfQvg==", "dev": true, "license": "MIT", "workspaces": [ @@ -4628,8 +3400,6 @@ }, "node_modules/eslint-plugin-playwright/node_modules/globals": { "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4644,8 +3414,6 @@ }, "node_modules/eslint-plugin-prettier": { "version": "5.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz", - "integrity": "sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw==", "dev": true, "license": "MIT", "dependencies": { @@ -4675,8 +3443,6 @@ }, "node_modules/eslint-plugin-vue": { "version": "9.32.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.32.0.tgz", - "integrity": "sha512-b/Y05HYmnB/32wqVcjxjHZzNpwxj1onBOvqW89W+V+XNG1dRuaFbNd3vT9CLbr2LXjEoq+3vn8DanWf7XU22Ug==", "dev": true, "license": "MIT", "dependencies": { @@ -4698,8 +3464,6 @@ }, "node_modules/eslint-plugin-vue/node_modules/globals": { "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4714,8 +3478,6 @@ }, "node_modules/eslint-scope": { "version": "8.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", - "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -4731,8 +3493,6 @@ }, "node_modules/eslint-visitor-keys": { "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "license": "Apache-2.0", "engines": { @@ -4744,8 +3504,6 @@ }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", "dependencies": { @@ -4755,8 +3513,6 @@ }, "node_modules/eslint/node_modules/eslint-visitor-keys": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -4768,8 +3524,6 @@ }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", "dependencies": { @@ -4781,8 +3535,6 @@ }, "node_modules/esm": { "version": "3.2.25", - "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", - "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", "license": "MIT", "engines": { "node": ">=6" @@ -4790,8 +3542,6 @@ }, "node_modules/espree": { "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -4808,8 +3558,6 @@ }, "node_modules/espree/node_modules/eslint-visitor-keys": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -4821,8 +3569,6 @@ }, "node_modules/esprima": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -4834,8 +3580,6 @@ }, "node_modules/esquery": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -4847,8 +3591,6 @@ }, "node_modules/esrecurse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -4860,8 +3602,6 @@ }, "node_modules/estraverse": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -4869,19 +3609,11 @@ } }, "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } + "version": "2.0.2", + "license": "MIT" }, "node_modules/esutils": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -4890,8 +3622,6 @@ }, "node_modules/etag": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -4899,8 +3629,6 @@ }, "node_modules/execa": { "version": "9.5.2", - "resolved": "https://registry.npmjs.org/execa/-/execa-9.5.2.tgz", - "integrity": "sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==", "dev": true, "license": "MIT", "dependencies": { @@ -4926,16 +3654,13 @@ }, "node_modules/expand-template": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "license": "(MIT OR WTFPL)", "engines": { "node": ">=6" } }, "node_modules/expect-type": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz", - "integrity": "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -4944,8 +3669,6 @@ }, "node_modules/express": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.0.1.tgz", - "integrity": "sha512-ORF7g6qGnD+YtUG9yx4DFoqCShNMmUKiXuT5oWMHiOvt/4WFbHC6yCwQMTSBMno7AqntNCAzzcnnjowRkTL9eQ==", "license": "MIT", "dependencies": { "accepts": "^2.0.0", @@ -4985,10 +3708,28 @@ "node": ">= 18" } }, + "node_modules/express-jwt": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-8.5.1.tgz", + "integrity": "sha512-Dv6QjDLpR2jmdb8M6XQXiCcpEom7mK8TOqnr0/TngDKsG2DHVkO8+XnVxkJVN7BuS1I3OrGw6N8j5DaaGgkDRQ==", + "license": "MIT", + "dependencies": { + "@types/jsonwebtoken": "^9", + "express-unless": "^2.1.3", + "jsonwebtoken": "^9.0.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/express-unless": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/express-unless/-/express-unless-2.1.3.tgz", + "integrity": "sha512-wj4tLMyCVYuIIKHGt0FhCtIViBcwzWejX0EjNxveAa6dG+0XBCQhMbx+PnkLkFCxLC69qoFrxds4pIyL88inaQ==", + "license": "MIT" + }, "node_modules/express/node_modules/debug": { "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "license": "MIT", "dependencies": { "ms": "2.1.2" @@ -5004,28 +3745,20 @@ }, "node_modules/express/node_modules/ms": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "license": "MIT" }, "node_modules/fast-deep-equal": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true, "license": "MIT" }, "node_modules/fast-diff": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", "dev": true, "license": "Apache-2.0" }, "node_modules/fast-glob": { "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -5040,8 +3773,6 @@ }, "node_modules/fast-glob/node_modules/glob-parent": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -5052,22 +3783,16 @@ }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, "license": "MIT" }, "node_modules/fastq": { "version": "1.19.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz", - "integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==", "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -5075,8 +3800,6 @@ }, "node_modules/figlet": { "version": "1.8.0", - "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.8.0.tgz", - "integrity": "sha512-chzvGjd+Sp7KUvPHZv6EXV5Ir3Q7kYNpCr4aHrRW79qFtTefmQZNny+W1pW9kf5zeE6dikku2W50W/wAH2xWgw==", "dev": true, "license": "MIT", "bin": { @@ -5088,8 +3811,6 @@ }, "node_modules/figures": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", - "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", "dev": true, "license": "MIT", "dependencies": { @@ -5104,8 +3825,6 @@ }, "node_modules/file-entry-cache": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5117,13 +3836,10 @@ }, "node_modules/file-uri-to-path": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + "license": "MIT" }, "node_modules/fill-range": { "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -5134,8 +3850,6 @@ }, "node_modules/finalhandler": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.0.0.tgz", - "integrity": "sha512-MX6Zo2adDViYh+GcxxB1dpO43eypOGUOL12rLCOTMQv/DfIbpSJUy4oQIIZhVZkH9e+bZWKMon0XHFEju16tkQ==", "license": "MIT", "dependencies": { "debug": "2.6.9", @@ -5152,8 +3866,6 @@ }, "node_modules/finalhandler/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -5161,8 +3873,6 @@ }, "node_modules/finalhandler/node_modules/encodeurl": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -5170,14 +3880,10 @@ }, "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, "node_modules/find-up": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", "dependencies": { @@ -5193,8 +3899,6 @@ }, "node_modules/flat-cache": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { @@ -5207,15 +3911,11 @@ }, "node_modules/flatted": { "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true, "license": "ISC" }, "node_modules/foreground-child": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, "license": "ISC", "dependencies": { @@ -5231,8 +3931,6 @@ }, "node_modules/form-data": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", - "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", "dev": true, "license": "MIT", "dependencies": { @@ -5247,8 +3945,6 @@ }, "node_modules/form-data/node_modules/mime-db": { "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, "license": "MIT", "engines": { @@ -5257,8 +3953,6 @@ }, "node_modules/form-data/node_modules/mime-types": { "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "license": "MIT", "dependencies": { @@ -5270,8 +3964,6 @@ }, "node_modules/forwarded": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -5279,8 +3971,6 @@ }, "node_modules/fresh": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -5288,13 +3978,10 @@ }, "node_modules/fs-constants": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + "license": "MIT" }, "node_modules/fs-extra": { "version": "11.3.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", - "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -5307,8 +3994,7 @@ }, "node_modules/fs-minipass": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -5318,8 +4004,7 @@ }, "node_modules/fs-minipass/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -5329,34 +4014,15 @@ }, "node_modules/fs-minipass/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "license": "ISC" }, "node_modules/fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC", "optional": true }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5364,9 +4030,7 @@ }, "node_modules/gauge": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "deprecated": "This package is no longer supported.", + "license": "ISC", "optional": true, "dependencies": { "aproba": "^1.0.3 || ^2.0.0", @@ -5384,8 +4048,7 @@ }, "node_modules/gauge/node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", "optional": true, "engines": { "node": ">=8" @@ -5393,20 +4056,17 @@ }, "node_modules/gauge/node_modules/emoji-regex": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT", "optional": true }, "node_modules/gauge/node_modules/signal-exit": { "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC", "optional": true }, "node_modules/gauge/node_modules/string-width": { "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "optional": true, "dependencies": { "emoji-regex": "^8.0.0", @@ -5419,8 +4079,7 @@ }, "node_modules/gauge/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "optional": true, "dependencies": { "ansi-regex": "^5.0.1" @@ -5431,8 +4090,6 @@ }, "node_modules/gensync": { "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, "license": "MIT", "engines": { @@ -5441,8 +4098,6 @@ }, "node_modules/get-caller-file": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, "license": "ISC", "engines": { @@ -5451,8 +4106,6 @@ }, "node_modules/get-intrinsic": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", - "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -5475,8 +4128,6 @@ }, "node_modules/get-package-type": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "license": "MIT", "engines": { "node": ">=8.0.0" @@ -5484,8 +4135,6 @@ }, "node_modules/get-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -5497,8 +4146,6 @@ }, "node_modules/get-stream": { "version": "9.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", - "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", "dev": true, "license": "MIT", "dependencies": { @@ -5514,8 +4161,6 @@ }, "node_modules/get-tsconfig": { "version": "4.10.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", - "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", "dev": true, "license": "MIT", "dependencies": { @@ -5527,19 +4172,14 @@ }, "node_modules/getopts": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.3.0.tgz", - "integrity": "sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==", "license": "MIT" }, "node_modules/github-from-package": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + "license": "MIT" }, "node_modules/glob": { "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "license": "ISC", "dependencies": { @@ -5559,8 +4199,6 @@ }, "node_modules/glob-parent": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "license": "ISC", "dependencies": { @@ -5572,8 +4210,6 @@ }, "node_modules/globals": { "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", "engines": { @@ -5585,8 +4221,6 @@ }, "node_modules/globby": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "license": "MIT", "dependencies": { "array-union": "^2.1.0", @@ -5605,8 +4239,6 @@ }, "node_modules/gopd": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -5617,21 +4249,15 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, "node_modules/graphemer": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true, "license": "MIT" }, "node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "license": "MIT", "engines": { @@ -5640,8 +4266,6 @@ }, "node_modules/has-symbols": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -5652,8 +4276,6 @@ }, "node_modules/has-tostringtag": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "license": "MIT", "dependencies": { @@ -5668,14 +4290,11 @@ }, "node_modules/has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC", "optional": true }, "node_modules/hasown": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -5686,8 +4305,6 @@ }, "node_modules/he": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, "license": "MIT", "bin": { @@ -5696,15 +4313,11 @@ }, "node_modules/hookable": { "version": "5.5.3", - "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", - "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", "dev": true, "license": "MIT" }, "node_modules/html-encoding-sniffer": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5716,8 +4329,6 @@ }, "node_modules/html-tags": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", - "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", "dev": true, "license": "MIT", "engines": { @@ -5729,14 +4340,11 @@ }, "node_modules/http-cache-semantics": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "license": "BSD-2-Clause", "optional": true }, "node_modules/http-errors": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "license": "MIT", "dependencies": { "depd": "2.0.0", @@ -5751,8 +4359,6 @@ }, "node_modules/http-proxy-agent": { "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, "license": "MIT", "dependencies": { @@ -5765,8 +4371,6 @@ }, "node_modules/https-proxy-agent": { "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, "license": "MIT", "dependencies": { @@ -5779,8 +4383,6 @@ }, "node_modules/human-signals": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz", - "integrity": "sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -5789,8 +4391,7 @@ }, "node_modules/humanize-ms": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", "optional": true, "dependencies": { "ms": "^2.0.0" @@ -5798,8 +4399,6 @@ }, "node_modules/iconv-lite": { "version": "0.5.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.2.tgz", - "integrity": "sha512-kERHXvpSaB4aU3eANwidg79K8FlrN77m8G9V+0vOR3HYaRifrlwMEpT7ZBJqLSEIHnEgJTHcWK82wwLwwKwtag==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" @@ -5810,8 +4409,6 @@ }, "node_modules/ieee754": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "funding": [ { "type": "github", @@ -5825,12 +4422,11 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "BSD-3-Clause" }, "node_modules/ignore": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "license": "MIT", "engines": { "node": ">= 4" @@ -5838,8 +4434,6 @@ }, "node_modules/import-fresh": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5855,8 +4449,6 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "devOptional": true, "license": "MIT", "engines": { @@ -5865,8 +4457,7 @@ }, "node_modules/indent-string": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "license": "MIT", "optional": true, "engines": { "node": ">=8" @@ -5874,15 +4465,12 @@ }, "node_modules/infer-owner": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "license": "ISC", "optional": true }, "node_modules/inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", "optional": true, "dependencies": { "once": "^1.3.0", @@ -5891,20 +4479,14 @@ }, "node_modules/inherits": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, "node_modules/ini": { "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "license": "ISC" }, "node_modules/interpret": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", "license": "MIT", "engines": { "node": ">= 0.10" @@ -5912,8 +4494,7 @@ }, "node_modules/ip-address": { "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "license": "MIT", "optional": true, "dependencies": { "jsbn": "1.1.0", @@ -5925,8 +4506,6 @@ }, "node_modules/ipaddr.js": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "license": "MIT", "engines": { "node": ">= 0.10" @@ -5934,8 +4513,6 @@ }, "node_modules/is-core-module": { "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -5949,8 +4526,6 @@ }, "node_modules/is-docker": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "dev": true, "license": "MIT", "bin": { @@ -5965,8 +4540,6 @@ }, "node_modules/is-extglob": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5974,8 +4547,6 @@ }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "devOptional": true, "license": "MIT", "engines": { @@ -5984,8 +4555,6 @@ }, "node_modules/is-glob": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -5996,8 +4565,6 @@ }, "node_modules/is-inside-container": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", "dev": true, "license": "MIT", "dependencies": { @@ -6015,14 +4582,11 @@ }, "node_modules/is-lambda": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "license": "MIT", "optional": true }, "node_modules/is-number": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "license": "MIT", "engines": { "node": ">=0.12.0" @@ -6030,8 +4594,6 @@ }, "node_modules/is-plain-obj": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "dev": true, "license": "MIT", "engines": { @@ -6043,21 +4605,15 @@ }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true, "license": "MIT" }, "node_modules/is-promise": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "license": "MIT" }, "node_modules/is-stream": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", - "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", "dev": true, "license": "MIT", "engines": { @@ -6069,8 +4625,6 @@ }, "node_modules/is-unicode-supported": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", - "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", "dev": true, "license": "MIT", "engines": { @@ -6082,8 +4636,6 @@ }, "node_modules/is-what": { "version": "4.1.16", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", - "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", "dev": true, "license": "MIT", "engines": { @@ -6095,8 +4647,6 @@ }, "node_modules/is-wsl": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", - "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", "dev": true, "license": "MIT", "dependencies": { @@ -6111,15 +4661,11 @@ }, "node_modules/isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "devOptional": true, "license": "ISC" }, "node_modules/jackspeak": { "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -6134,18 +4680,23 @@ }, "node_modules/jiti": { "version": "2.4.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", - "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", "dev": true, "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/jose": { + "version": "4.15.9", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", + "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-beautify": { "version": "1.15.3", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.3.tgz", - "integrity": "sha512-rKKGuyTxGNlyN4EQKWzNndzXpi0bOl8Gl8YQAW1as/oMz0XhD6sHJO1hTvoBDOSzKuJb9WkwoAb34FfdkKMv2A==", "dev": true, "license": "MIT", "dependencies": { @@ -6166,8 +4717,6 @@ }, "node_modules/js-cookie": { "version": "3.0.5", - "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", - "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", "dev": true, "license": "MIT", "engines": { @@ -6176,15 +4725,11 @@ }, "node_modules/js-tokens": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true, "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -6195,14 +4740,11 @@ }, "node_modules/jsbn": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "license": "MIT", "optional": true }, "node_modules/jsdom": { "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.0.0.tgz", - "integrity": "sha512-BZYDGVAIriBWTpIxYzrXjv3E/4u8+/pSG5bQdIYCbNCGOvsPkDQfTVLAIXAf9ETdCpduCVTkDe2NNZ8NIwUVzw==", "dev": true, "license": "MIT", "dependencies": { @@ -6242,8 +4784,6 @@ }, "node_modules/jsdom/node_modules/xml-name-validator": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", "dev": true, "license": "Apache-2.0", "engines": { @@ -6252,8 +4792,6 @@ }, "node_modules/jsesc": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, "license": "MIT", "bin": { @@ -6265,15 +4803,11 @@ }, "node_modules/json-buffer": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, "license": "MIT" }, "node_modules/json-parse-even-better-errors": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-4.0.0.tgz", - "integrity": "sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==", "dev": true, "license": "MIT", "engines": { @@ -6282,22 +4816,16 @@ }, "node_modules/json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, "license": "MIT" }, "node_modules/json5": { "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "license": "MIT", "bin": { @@ -6309,8 +4837,6 @@ }, "node_modules/jsonfile": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "license": "MIT", "dependencies": { "universalify": "^2.0.0" @@ -6319,10 +4845,92 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jwks-rsa": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.1.0.tgz", + "integrity": "sha512-v7nqlfezb9YfHHzYII3ef2a2j1XnGeSE/bK3WfumaYCqONAIstJbrEGapz4kadScZzEt7zYCN7bucj8C0Mv/Rg==", + "license": "MIT", + "dependencies": { + "@types/express": "^4.17.17", + "@types/jsonwebtoken": "^9.0.2", + "debug": "^4.3.4", + "jose": "^4.14.6", + "limiter": "^1.1.5", + "lru-memoizer": "^2.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/jwks-rsa/node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/jwks-rsa/node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keyv": { "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "license": "MIT", "dependencies": { @@ -6331,8 +4939,6 @@ }, "node_modules/knex": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/knex/-/knex-3.1.0.tgz", - "integrity": "sha512-GLoII6hR0c4ti243gMs5/1Rb3B+AjwMOfjYm97pu0FOQa7JH56hgBxYf5WK2525ceSbBY1cjeZ9yk99GPMB6Kw==", "license": "MIT", "dependencies": { "colorette": "2.0.19", @@ -6382,8 +4988,6 @@ }, "node_modules/knex/node_modules/debug": { "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "license": "MIT", "dependencies": { "ms": "2.1.2" @@ -6399,14 +5003,10 @@ }, "node_modules/knex/node_modules/ms": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "license": "MIT" }, "node_modules/knex/node_modules/resolve-from": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "license": "MIT", "engines": { "node": ">=8" @@ -6414,15 +5014,11 @@ }, "node_modules/kolorist": { "version": "1.8.0", - "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", - "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", "dev": true, "license": "MIT" }, "node_modules/levn": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6433,10 +5029,13 @@ "node": ">= 0.8.0" } }, + "node_modules/limiter": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", + "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" + }, "node_modules/locate-path": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", "dependencies": { @@ -6451,35 +5050,101 @@ }, "node_modules/lodash": { "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "license": "MIT" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, "license": "MIT" }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, "node_modules/loupe": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", - "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==", "dev": true, "license": "MIT" }, "node_modules/lru-cache": { "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, "license": "ISC" }, + "node_modules/lru-memoizer": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.3.0.tgz", + "integrity": "sha512-GXn7gyHAMhO13WSKrIiNfztwxodVsP8IoZ3XfrJV4yH2x0/OeTO/FIaAHTY5YekdGgW94njfuKmyyt1E0mR6Ug==", + "license": "MIT", + "dependencies": { + "lodash.clonedeep": "^4.5.0", + "lru-cache": "6.0.0" + } + }, + "node_modules/lru-memoizer/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lru-memoizer/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/magic-string": { "version": "0.30.17", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", - "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" @@ -6487,15 +5152,12 @@ }, "node_modules/make-error": { "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true, "license": "ISC" }, "node_modules/make-fetch-happen": { "version": "9.1.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", - "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "license": "ISC", "optional": true, "dependencies": { "agentkeepalive": "^4.1.3", @@ -6521,8 +5183,7 @@ }, "node_modules/make-fetch-happen/node_modules/agent-base": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", "optional": true, "dependencies": { "debug": "4" @@ -6533,8 +5194,7 @@ }, "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "license": "MIT", "optional": true, "dependencies": { "@tootallnate/once": "1", @@ -6547,8 +5207,7 @@ }, "node_modules/make-fetch-happen/node_modules/https-proxy-agent": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", "optional": true, "dependencies": { "agent-base": "6", @@ -6560,8 +5219,7 @@ }, "node_modules/make-fetch-happen/node_modules/lru-cache": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", "optional": true, "dependencies": { "yallist": "^4.0.0" @@ -6572,8 +5230,7 @@ }, "node_modules/make-fetch-happen/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "optional": true, "dependencies": { "yallist": "^4.0.0" @@ -6584,8 +5241,7 @@ }, "node_modules/make-fetch-happen/node_modules/negotiator": { "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", "optional": true, "engines": { "node": ">= 0.6" @@ -6593,14 +5249,11 @@ }, "node_modules/make-fetch-happen/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC", "optional": true }, "node_modules/math-intrinsics": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -6608,8 +5261,6 @@ }, "node_modules/media-typer": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -6617,8 +5268,6 @@ }, "node_modules/memorystream": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", "dev": true, "engines": { "node": ">= 0.10.0" @@ -6626,8 +5275,6 @@ }, "node_modules/merge-descriptors": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "license": "MIT", "engines": { "node": ">=18" @@ -6638,8 +5285,6 @@ }, "node_modules/merge2": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "license": "MIT", "engines": { "node": ">= 8" @@ -6647,8 +5292,6 @@ }, "node_modules/methods": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -6656,8 +5299,6 @@ }, "node_modules/micromatch": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -6669,8 +5310,6 @@ }, "node_modules/mikro-orm": { "version": "6.4.6", - "resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-6.4.6.tgz", - "integrity": "sha512-Lr3uFK06O/4F/AtQAsuYD6QH7DgmUooSVFVGf1y02IuiKVFKOMJ4iKimkRMyoA+ykKhgYIp8WiaEqbWJVuz4Vw==", "license": "MIT", "engines": { "node": ">= 18.12.0" @@ -6678,8 +5317,6 @@ }, "node_modules/mime-db": { "version": "1.53.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz", - "integrity": "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -6687,8 +5324,6 @@ }, "node_modules/mime-types": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.0.tgz", - "integrity": "sha512-XqoSHeCGjVClAmoGFG3lVFqQFRIrTVw2OH3axRqAcfaw+gHWIfnASS92AV+Rl/mk0MupgZTRHQOjxY6YVnzK5w==", "license": "MIT", "dependencies": { "mime-db": "^1.53.0" @@ -6699,8 +5334,7 @@ }, "node_modules/mimic-response": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -6710,8 +5344,6 @@ }, "node_modules/minimatch": { "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -6725,8 +5357,6 @@ }, "node_modules/minimist": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6734,8 +5364,6 @@ }, "node_modules/minipass": { "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, "license": "ISC", "engines": { @@ -6744,8 +5372,7 @@ }, "node_modules/minipass-collect": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "license": "ISC", "optional": true, "dependencies": { "minipass": "^3.0.0" @@ -6756,8 +5383,7 @@ }, "node_modules/minipass-collect/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "optional": true, "dependencies": { "yallist": "^4.0.0" @@ -6768,14 +5394,12 @@ }, "node_modules/minipass-collect/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC", "optional": true }, "node_modules/minipass-fetch": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", - "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "license": "MIT", "optional": true, "dependencies": { "minipass": "^3.1.0", @@ -6791,8 +5415,7 @@ }, "node_modules/minipass-fetch/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "optional": true, "dependencies": { "yallist": "^4.0.0" @@ -6803,14 +5426,12 @@ }, "node_modules/minipass-fetch/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC", "optional": true }, "node_modules/minipass-flush": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "license": "ISC", "optional": true, "dependencies": { "minipass": "^3.0.0" @@ -6821,8 +5442,7 @@ }, "node_modules/minipass-flush/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "optional": true, "dependencies": { "yallist": "^4.0.0" @@ -6833,14 +5453,12 @@ }, "node_modules/minipass-flush/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC", "optional": true }, "node_modules/minipass-pipeline": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "license": "ISC", "optional": true, "dependencies": { "minipass": "^3.0.0" @@ -6851,8 +5469,7 @@ }, "node_modules/minipass-pipeline/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "optional": true, "dependencies": { "yallist": "^4.0.0" @@ -6863,14 +5480,12 @@ }, "node_modules/minipass-pipeline/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC", "optional": true }, "node_modules/minipass-sized": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "license": "ISC", "optional": true, "dependencies": { "minipass": "^3.0.0" @@ -6881,8 +5496,7 @@ }, "node_modules/minipass-sized/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "optional": true, "dependencies": { "yallist": "^4.0.0" @@ -6893,14 +5507,12 @@ }, "node_modules/minipass-sized/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC", "optional": true }, "node_modules/minizlib": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -6911,8 +5523,7 @@ }, "node_modules/minizlib/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -6922,20 +5533,16 @@ }, "node_modules/minizlib/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "license": "ISC" }, "node_modules/mitt": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", - "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", "dev": true, "license": "MIT" }, "node_modules/mkdirp": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -6945,13 +5552,10 @@ }, "node_modules/mkdirp-classic": { "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + "license": "MIT" }, "node_modules/mrmime": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", - "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", "dev": true, "license": "MIT", "engines": { @@ -6960,21 +5564,15 @@ }, "node_modules/ms": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/muggle-string": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", - "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", "dev": true, "license": "MIT" }, "node_modules/nanoid": { "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "funding": [ { "type": "github", @@ -6991,20 +5589,15 @@ }, "node_modules/napi-build-utils": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", - "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==" + "license": "MIT" }, "node_modules/natural-compare": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true, "license": "MIT" }, "node_modules/negotiator": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -7012,8 +5605,7 @@ }, "node_modules/node-abi": { "version": "3.74.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.74.0.tgz", - "integrity": "sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==", + "license": "MIT", "dependencies": { "semver": "^7.3.5" }, @@ -7023,13 +5615,11 @@ }, "node_modules/node-addon-api": { "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==" + "license": "MIT" }, "node_modules/node-gyp": { "version": "8.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", - "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "license": "MIT", "optional": true, "dependencies": { "env-paths": "^2.2.0", @@ -7052,14 +5642,12 @@ }, "node_modules/node-gyp/node_modules/abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "license": "ISC", "optional": true }, "node_modules/node-gyp/node_modules/brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", "optional": true, "dependencies": { "balanced-match": "^1.0.0", @@ -7068,9 +5656,7 @@ }, "node_modules/node-gyp/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", "optional": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -7089,8 +5675,7 @@ }, "node_modules/node-gyp/node_modules/minimatch": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", "optional": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -7101,8 +5686,7 @@ }, "node_modules/node-gyp/node_modules/nopt": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "license": "ISC", "optional": true, "dependencies": { "abbrev": "1" @@ -7116,15 +5700,11 @@ }, "node_modules/node-releases": { "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", "dev": true, "license": "MIT" }, "node_modules/nopt": { "version": "8.1.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", - "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", "dev": true, "license": "ISC", "dependencies": { @@ -7139,8 +5719,6 @@ }, "node_modules/npm-normalize-package-bin": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz", - "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==", "dev": true, "license": "ISC", "engines": { @@ -7149,8 +5727,6 @@ }, "node_modules/npm-run-all2": { "version": "7.0.2", - "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-7.0.2.tgz", - "integrity": "sha512-7tXR+r9hzRNOPNTvXegM+QzCuMjzUIIq66VDunL6j60O4RrExx32XUhlrS7UK4VcdGw5/Wxzb3kfNcFix9JKDA==", "dev": true, "license": "MIT", "dependencies": { @@ -7176,8 +5752,6 @@ }, "node_modules/npm-run-all2/node_modules/ansi-styles": { "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, "license": "MIT", "engines": { @@ -7189,8 +5763,6 @@ }, "node_modules/npm-run-all2/node_modules/isexe": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, "license": "ISC", "engines": { @@ -7199,8 +5771,6 @@ }, "node_modules/npm-run-all2/node_modules/which": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", - "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", "dev": true, "license": "ISC", "dependencies": { @@ -7215,8 +5785,6 @@ }, "node_modules/npm-run-path": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", - "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", "dev": true, "license": "MIT", "dependencies": { @@ -7232,8 +5800,6 @@ }, "node_modules/npm-run-path/node_modules/path-key": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, "license": "MIT", "engines": { @@ -7245,9 +5811,7 @@ }, "node_modules/npmlog": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "deprecated": "This package is no longer supported.", + "license": "ISC", "optional": true, "dependencies": { "are-we-there-yet": "^3.0.0", @@ -7261,8 +5825,6 @@ }, "node_modules/nth-check": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -7274,15 +5836,11 @@ }, "node_modules/nwsapi": { "version": "2.2.16", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz", - "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==", "dev": true, "license": "MIT" }, "node_modules/object-inspect": { "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -7293,8 +5851,6 @@ }, "node_modules/on-finished": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "license": "MIT", "dependencies": { "ee-first": "1.1.1" @@ -7305,8 +5861,6 @@ }, "node_modules/once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "license": "ISC", "dependencies": { "wrappy": "1" @@ -7314,8 +5868,6 @@ }, "node_modules/open": { "version": "10.1.0", - "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", - "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", "dev": true, "license": "MIT", "dependencies": { @@ -7333,8 +5885,6 @@ }, "node_modules/optionator": { "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", "dependencies": { @@ -7351,8 +5901,6 @@ }, "node_modules/p-limit": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7367,8 +5915,6 @@ }, "node_modules/p-locate": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", "dependencies": { @@ -7383,8 +5929,7 @@ }, "node_modules/p-map": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "license": "MIT", "optional": true, "dependencies": { "aggregate-error": "^3.0.0" @@ -7398,15 +5943,11 @@ }, "node_modules/package-json-from-dist": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true, "license": "BlueOak-1.0.0" }, "node_modules/parent-module": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "license": "MIT", "dependencies": { @@ -7418,8 +5959,6 @@ }, "node_modules/parent-require": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parent-require/-/parent-require-1.0.0.tgz", - "integrity": "sha512-2MXDNZC4aXdkkap+rBBMv0lUsfJqvX5/2FiYYnfCnorZt3Pk06/IOR5KeaoghgS2w07MLWgjbsnyaq6PdHn2LQ==", "dev": true, "engines": { "node": ">= 0.4.0" @@ -7427,8 +5966,6 @@ }, "node_modules/parse-ms": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", - "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", "dev": true, "license": "MIT", "engines": { @@ -7440,8 +5977,6 @@ }, "node_modules/parse5": { "version": "7.2.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", - "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7453,8 +5988,6 @@ }, "node_modules/parseurl": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -7462,14 +5995,10 @@ }, "node_modules/path-browserify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", "license": "MIT" }, "node_modules/path-exists": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "license": "MIT", "engines": { @@ -7478,8 +6007,7 @@ }, "node_modules/path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", "optional": true, "engines": { "node": ">=0.10.0" @@ -7487,8 +6015,6 @@ }, "node_modules/path-key": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, "license": "MIT", "engines": { @@ -7497,14 +6023,10 @@ }, "node_modules/path-parse": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "license": "MIT" }, "node_modules/path-scurry": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -7520,8 +6042,6 @@ }, "node_modules/path-to-regexp": { "version": "8.2.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", - "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", "license": "MIT", "engines": { "node": ">=16" @@ -7529,8 +6049,6 @@ }, "node_modules/path-type": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "license": "MIT", "engines": { "node": ">=8" @@ -7538,15 +6056,11 @@ }, "node_modules/pathe": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, "license": "MIT" }, "node_modules/pathval": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", - "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", "dev": true, "license": "MIT", "engines": { @@ -7555,15 +6069,11 @@ }, "node_modules/perfect-debounce": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", - "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", "dev": true, "license": "MIT" }, "node_modules/pg": { "version": "8.13.2", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.13.2.tgz", - "integrity": "sha512-L5QkPvTjVWWHbLaFjCkOSplpb2uCiRYbg0IJ2okCy5ClYfWlSgDDnvdR6dyw3EWAH2AfS4j8E61QFI7gLfTtlw==", "license": "MIT", "dependencies": { "pg-connection-string": "^2.7.0", @@ -7589,21 +6099,15 @@ }, "node_modules/pg-cloudflare": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", - "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", "license": "MIT", "optional": true }, "node_modules/pg-connection-string": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", - "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==", "license": "MIT" }, "node_modules/pg-int8": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", "license": "ISC", "engines": { "node": ">=4.0.0" @@ -7611,8 +6115,6 @@ }, "node_modules/pg-pool": { "version": "3.7.1", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.1.tgz", - "integrity": "sha512-xIOsFoh7Vdhojas6q3596mXFsR8nwBQBXX5JiV7p9buEVAGqYL4yFzclON5P9vFrpu1u7Zwl2oriyDa89n0wbw==", "license": "MIT", "peerDependencies": { "pg": ">=8.0" @@ -7620,14 +6122,10 @@ }, "node_modules/pg-protocol": { "version": "1.7.1", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.1.tgz", - "integrity": "sha512-gjTHWGYWsEgy9MsY0Gp6ZJxV24IjDqdpTW7Eh0x+WfJLFsm/TJx1MzL6T0D88mBvkpxotCQ6TwW6N+Kko7lhgQ==", "license": "MIT" }, "node_modules/pg-types": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", "license": "MIT", "dependencies": { "pg-int8": "1.0.1", @@ -7642,8 +6140,6 @@ }, "node_modules/pg-types/node_modules/postgres-array": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", "license": "MIT", "engines": { "node": ">=4" @@ -7651,8 +6147,6 @@ }, "node_modules/pg-types/node_modules/postgres-date": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7660,8 +6154,6 @@ }, "node_modules/pg-types/node_modules/postgres-interval": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", "license": "MIT", "dependencies": { "xtend": "^4.0.0" @@ -7672,14 +6164,10 @@ }, "node_modules/pg/node_modules/pg-connection-string": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.7.0.tgz", - "integrity": "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==", "license": "MIT" }, "node_modules/pgpass": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", - "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", "license": "MIT", "dependencies": { "split2": "^4.1.0" @@ -7687,14 +6175,10 @@ }, "node_modules/picocolors": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -7705,8 +6189,6 @@ }, "node_modules/pidtree": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", - "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", "dev": true, "license": "MIT", "bin": { @@ -7718,8 +6200,6 @@ }, "node_modules/playwright": { "version": "1.50.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.50.1.tgz", - "integrity": "sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -7737,8 +6217,6 @@ }, "node_modules/playwright-core": { "version": "1.50.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.1.tgz", - "integrity": "sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -7748,25 +6226,8 @@ "node": ">=18" } }, - "node_modules/playwright/node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/postcss": { "version": "8.5.3", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", - "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", "funding": [ { "type": "opencollective", @@ -7793,8 +6254,6 @@ }, "node_modules/postcss-selector-parser": { "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dev": true, "license": "MIT", "dependencies": { @@ -7807,8 +6266,6 @@ }, "node_modules/postgres-array": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz", - "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==", "license": "MIT", "engines": { "node": ">=12" @@ -7816,8 +6273,6 @@ }, "node_modules/postgres-bytea": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", - "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7825,8 +6280,6 @@ }, "node_modules/postgres-date": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz", - "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==", "license": "MIT", "engines": { "node": ">=12" @@ -7834,8 +6287,6 @@ }, "node_modules/postgres-interval": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-4.0.2.tgz", - "integrity": "sha512-EMsphSQ1YkQqKZL2cuG0zHkmjCCzQqQ71l2GXITqRwjhRleCdv00bDk/ktaSi0LnlaPzAc3535KTrjXsTdtx7A==", "license": "MIT", "engines": { "node": ">=12" @@ -7843,8 +6294,7 @@ }, "node_modules/prebuild-install": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", - "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "license": "MIT", "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", @@ -7868,8 +6318,6 @@ }, "node_modules/prelude-ls": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", "engines": { @@ -7878,8 +6326,6 @@ }, "node_modules/prettier": { "version": "3.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.1.tgz", - "integrity": "sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw==", "dev": true, "license": "MIT", "peer": true, @@ -7895,8 +6341,6 @@ }, "node_modules/prettier-linter-helpers": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, "license": "MIT", "dependencies": { @@ -7908,8 +6352,6 @@ }, "node_modules/pretty-ms": { "version": "9.2.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.2.0.tgz", - "integrity": "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==", "dev": true, "license": "MIT", "dependencies": { @@ -7924,14 +6366,12 @@ }, "node_modules/promise-inflight": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "license": "ISC", "optional": true }, "node_modules/promise-retry": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "license": "MIT", "optional": true, "dependencies": { "err-code": "^2.0.2", @@ -7943,15 +6383,11 @@ }, "node_modules/proto-list": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", "dev": true, "license": "ISC" }, "node_modules/proxy-addr": { "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "license": "MIT", "dependencies": { "forwarded": "0.2.0", @@ -7963,8 +6399,7 @@ }, "node_modules/pump": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", - "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -7972,8 +6407,6 @@ }, "node_modules/punycode": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", "engines": { @@ -7982,8 +6415,6 @@ }, "node_modules/qs": { "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.6" @@ -7997,8 +6428,6 @@ }, "node_modules/queue-microtask": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "funding": [ { "type": "github", @@ -8017,8 +6446,6 @@ }, "node_modules/range-parser": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -8026,8 +6453,6 @@ }, "node_modules/raw-body": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", - "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", "license": "MIT", "dependencies": { "bytes": "3.1.2", @@ -8041,8 +6466,6 @@ }, "node_modules/raw-body/node_modules/iconv-lite": { "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -8053,8 +6476,7 @@ }, "node_modules/rc": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -8067,16 +6489,13 @@ }, "node_modules/rc/node_modules/strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/read-package-json-fast": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-4.0.0.tgz", - "integrity": "sha512-qpt8EwugBWDw2cgE2W+/3oxC+KTez2uSVR8JU9Q36TXPAGCaozfQUs59v4j4GFpWTaw0i6hAZSvOmu1J0uOEUg==", "dev": true, "license": "ISC", "dependencies": { @@ -8089,8 +6508,7 @@ }, "node_modules/readable-stream": { "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -8102,8 +6520,6 @@ }, "node_modules/rechoir": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", - "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "license": "MIT", "dependencies": { "resolve": "^1.20.0" @@ -8114,14 +6530,10 @@ }, "node_modules/reflect-metadata": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", - "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", "license": "Apache-2.0" }, "node_modules/require-directory": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "license": "MIT", "engines": { @@ -8130,8 +6542,6 @@ }, "node_modules/resolve": { "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "license": "MIT", "dependencies": { "is-core-module": "^2.16.0", @@ -8150,8 +6560,6 @@ }, "node_modules/resolve-from": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "license": "MIT", "engines": { @@ -8160,8 +6568,6 @@ }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "dev": true, "license": "MIT", "funding": { @@ -8170,8 +6576,7 @@ }, "node_modules/retry": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "license": "MIT", "optional": true, "engines": { "node": ">= 4" @@ -8179,8 +6584,6 @@ }, "node_modules/reusify": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -8189,16 +6592,12 @@ }, "node_modules/rfdc": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "dev": true, "license": "MIT" }, "node_modules/rimraf": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", "optional": true, "dependencies": { "glob": "^7.1.3" @@ -8212,8 +6611,7 @@ }, "node_modules/rimraf/node_modules/brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", "optional": true, "dependencies": { "balanced-match": "^1.0.0", @@ -8222,9 +6620,7 @@ }, "node_modules/rimraf/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", "optional": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -8243,8 +6639,7 @@ }, "node_modules/rimraf/node_modules/minimatch": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", "optional": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -8255,8 +6650,6 @@ }, "node_modules/rollup": { "version": "4.34.8", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz", - "integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8294,8 +6687,6 @@ }, "node_modules/router": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.1.0.tgz", - "integrity": "sha512-/m/NSLxeYEgWNtyC+WtNHCF7jbGxOibVWKnn+1Psff4dJGOfoXP+MuC/f2CwSmyiHdOIzYnYFp4W6GxWfekaLA==", "license": "MIT", "dependencies": { "is-promise": "^4.0.0", @@ -8308,15 +6699,11 @@ }, "node_modules/rrweb-cssom": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", - "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", "dev": true, "license": "MIT" }, "node_modules/run-applescript": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", - "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", "dev": true, "license": "MIT", "engines": { @@ -8328,8 +6715,6 @@ }, "node_modules/run-parallel": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "funding": [ { "type": "github", @@ -8351,8 +6736,6 @@ }, "node_modules/safe-buffer": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -8371,14 +6754,10 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, "node_modules/saxes": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, "license": "ISC", "dependencies": { @@ -8390,8 +6769,6 @@ }, "node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -8402,8 +6779,6 @@ }, "node_modules/send": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.1.0.tgz", - "integrity": "sha512-v67WcEouB5GxbTWL/4NeToqcZiAWEq90N888fczVArY8A79J0L4FD7vj5hm3eUMua5EpoQ59wa/oovY6TLvRUA==", "license": "MIT", "dependencies": { "debug": "^4.3.5", @@ -8425,8 +6800,6 @@ }, "node_modules/send/node_modules/fresh": { "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -8434,8 +6807,6 @@ }, "node_modules/send/node_modules/mime-db": { "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -8443,8 +6814,6 @@ }, "node_modules/send/node_modules/mime-types": { "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -8455,8 +6824,6 @@ }, "node_modules/serve-static": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.1.0.tgz", - "integrity": "sha512-A3We5UfEjG8Z7VkDv6uItWw6HY2bBSBJT1KtVESn6EOoOr2jAxNhxWCLY3jDE2WcuHXByWju74ck3ZgLwL8xmA==", "license": "MIT", "dependencies": { "encodeurl": "^2.0.0", @@ -8470,20 +6837,15 @@ }, "node_modules/set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC", "optional": true }, "node_modules/setprototypeof": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, "node_modules/shebang-command": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "license": "MIT", "dependencies": { @@ -8495,8 +6857,6 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, "license": "MIT", "engines": { @@ -8505,8 +6865,6 @@ }, "node_modules/shell-quote": { "version": "1.8.2", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", - "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", "dev": true, "license": "MIT", "engines": { @@ -8518,8 +6876,6 @@ }, "node_modules/side-channel": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -8537,8 +6893,6 @@ }, "node_modules/side-channel-list": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -8553,8 +6907,6 @@ }, "node_modules/side-channel-map": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -8571,8 +6923,6 @@ }, "node_modules/side-channel-weakmap": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -8590,15 +6940,11 @@ }, "node_modules/siginfo": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "dev": true, "license": "ISC" }, "node_modules/signal-exit": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, "license": "ISC", "engines": { @@ -8610,27 +6956,6 @@ }, "node_modules/simple-concat": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", "funding": [ { "type": "github", @@ -8645,6 +6970,25 @@ "url": "https://feross.org/support" } ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", @@ -8653,8 +6997,6 @@ }, "node_modules/sirv": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", - "integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==", "dev": true, "license": "MIT", "dependencies": { @@ -8668,8 +7010,6 @@ }, "node_modules/slash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "license": "MIT", "engines": { "node": ">=8" @@ -8677,8 +7017,7 @@ }, "node_modules/smart-buffer": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", "optional": true, "engines": { "node": ">= 6.0.0", @@ -8687,8 +7026,7 @@ }, "node_modules/socks": { "version": "2.8.4", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz", - "integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==", + "license": "MIT", "optional": true, "dependencies": { "ip-address": "^9.0.5", @@ -8701,8 +7039,7 @@ }, "node_modules/socks-proxy-agent": { "version": "6.2.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", - "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "license": "MIT", "optional": true, "dependencies": { "agent-base": "^6.0.2", @@ -8715,8 +7052,7 @@ }, "node_modules/socks-proxy-agent/node_modules/agent-base": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", "optional": true, "dependencies": { "debug": "4" @@ -8727,8 +7063,6 @@ }, "node_modules/source-map-js": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -8736,8 +7070,6 @@ }, "node_modules/speakingurl": { "version": "14.0.1", - "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", - "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -8746,8 +7078,6 @@ }, "node_modules/split2": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "license": "ISC", "engines": { "node": ">= 10.x" @@ -8755,15 +7085,13 @@ }, "node_modules/sprintf-js": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "license": "BSD-3-Clause", "optional": true }, "node_modules/sqlite3": { "version": "5.1.7", - "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.7.tgz", - "integrity": "sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==", "hasInstallScript": true, + "license": "BSD-3-Clause", "dependencies": { "bindings": "^1.5.0", "node-addon-api": "^7.0.0", @@ -8784,8 +7112,6 @@ }, "node_modules/sqlstring": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", - "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -8793,16 +7119,14 @@ }, "node_modules/sqlstring-sqlite": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/sqlstring-sqlite/-/sqlstring-sqlite-0.1.1.tgz", - "integrity": "sha512-9CAYUJ0lEUPYJrswqiqdINNSfq3jqWo/bFJ7tufdoNeSK0Fy+d1kFTxjqO9PIqza0Kri+ZtYMfPVf1aZaFOvrQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/ssri": { "version": "8.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "license": "ISC", "optional": true, "dependencies": { "minipass": "^3.1.1" @@ -8813,8 +7137,7 @@ }, "node_modules/ssri/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "optional": true, "dependencies": { "yallist": "^4.0.0" @@ -8825,21 +7148,16 @@ }, "node_modules/ssri/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC", "optional": true }, "node_modules/stackback": { "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "dev": true, "license": "MIT" }, "node_modules/statuses": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -8847,23 +7165,35 @@ }, "node_modules/std-env": { "version": "3.8.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz", - "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==", "dev": true, "license": "MIT" }, "node_modules/string_decoder": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } }, "node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { @@ -8875,26 +7205,47 @@ "node": ">=8" } }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" } }, "node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { @@ -8904,24 +7255,16 @@ "node": ">=8" } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", "dev": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, "engines": { "node": ">=8" } }, "node_modules/strip-bom": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, "license": "MIT", "engines": { @@ -8930,8 +7273,6 @@ }, "node_modules/strip-final-newline": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", - "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", "dev": true, "license": "MIT", "engines": { @@ -8943,8 +7284,6 @@ }, "node_modules/strip-json-comments": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "license": "MIT", "engines": { @@ -8956,8 +7295,6 @@ }, "node_modules/superjson": { "version": "2.2.2", - "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz", - "integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==", "dev": true, "license": "MIT", "dependencies": { @@ -8969,8 +7306,6 @@ }, "node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", "dependencies": { @@ -8982,8 +7317,6 @@ }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -8994,21 +7327,15 @@ }, "node_modules/svg-tags": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", - "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", "dev": true }, "node_modules/symbol-tree": { "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true, "license": "MIT" }, "node_modules/synckit": { "version": "0.9.2", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", - "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", "dev": true, "license": "MIT", "dependencies": { @@ -9024,8 +7351,7 @@ }, "node_modules/tar": { "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "license": "ISC", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -9040,8 +7366,7 @@ }, "node_modules/tar-fs": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", - "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", + "license": "MIT", "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", @@ -9051,13 +7376,11 @@ }, "node_modules/tar-fs/node_modules/chownr": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + "license": "ISC" }, "node_modules/tar-stream": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -9071,21 +7394,17 @@ }, "node_modules/tar/node_modules/minipass": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", "engines": { "node": ">=8" } }, "node_modules/tar/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "license": "ISC" }, "node_modules/tarn": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz", - "integrity": "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==", "license": "MIT", "engines": { "node": ">=8.0.0" @@ -9093,8 +7412,6 @@ }, "node_modules/tildify": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", - "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==", "license": "MIT", "engines": { "node": ">=8" @@ -9102,22 +7419,16 @@ }, "node_modules/tinybench": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", "dev": true, "license": "MIT" }, "node_modules/tinyexec": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", "dev": true, "license": "MIT" }, "node_modules/tinypool": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz", - "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==", "dev": true, "license": "MIT", "engines": { @@ -9126,8 +7437,6 @@ }, "node_modules/tinyrainbow": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", - "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", "dev": true, "license": "MIT", "engines": { @@ -9136,8 +7445,6 @@ }, "node_modules/tinyspy": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", - "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", "dev": true, "license": "MIT", "engines": { @@ -9145,29 +7452,23 @@ } }, "node_modules/tldts": { - "version": "6.1.78", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.78.tgz", - "integrity": "sha512-fSgYrW0ITH0SR/CqKMXIruYIPpNu5aDgUp22UhYoSrnUQwc7SBqifEBFNce7AAcygUPBo6a/gbtcguWdmko4RQ==", + "version": "6.1.77", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^6.1.78" + "tldts-core": "^6.1.77" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "6.1.78", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.78.tgz", - "integrity": "sha512-jS0svNsB99jR6AJBmfmEWuKIgz91Haya91Z43PATaeHJ24BkMoNRb/jlaD37VYjb0mYf6gRL/HOnvS1zEnYBiw==", + "version": "6.1.77", "dev": true, "license": "MIT" }, "node_modules/to-regex-range": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -9178,8 +7479,6 @@ }, "node_modules/toidentifier": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "license": "MIT", "engines": { "node": ">=0.6" @@ -9187,8 +7486,6 @@ }, "node_modules/totalist": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", - "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", "dev": true, "license": "MIT", "engines": { @@ -9197,8 +7494,6 @@ }, "node_modules/tough-cookie": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.1.tgz", - "integrity": "sha512-Ek7HndSVkp10hmHP9V4qZO1u+pn1RU5sI0Fw+jCU3lyvuMZcgqsNgc6CmJJZyByK4Vm/qotGRJlfgAX8q+4JiA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -9210,8 +7505,6 @@ }, "node_modules/tr46": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", - "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", "dev": true, "license": "MIT", "dependencies": { @@ -9223,8 +7516,6 @@ }, "node_modules/ts-api-utils": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", - "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", "dev": true, "license": "MIT", "engines": { @@ -9236,8 +7527,6 @@ }, "node_modules/ts-morph": { "version": "25.0.1", - "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-25.0.1.tgz", - "integrity": "sha512-QJEiTdnz1YjrB3JFhd626gX4rKHDLSjSVMvGGG4v7ONc3RBwa0Eei98G9AT9uNFDMtV54JyuXsFeC+OH0n6bXQ==", "license": "MIT", "dependencies": { "@ts-morph/common": "~0.26.0", @@ -9246,8 +7535,6 @@ }, "node_modules/ts-node": { "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9290,8 +7577,6 @@ }, "node_modules/tsconfig-paths": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", "dev": true, "license": "MIT", "dependencies": { @@ -9305,15 +7590,11 @@ }, "node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD" }, "node_modules/tsx": { "version": "4.19.3", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.3.tgz", - "integrity": "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9330,26 +7611,9 @@ "fsevents": "~2.3.3" } }, - "node_modules/tsx/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/tunnel-agent": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" }, @@ -9359,8 +7623,6 @@ }, "node_modules/type-check": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "license": "MIT", "dependencies": { @@ -9372,8 +7634,6 @@ }, "node_modules/type-fest": { "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { @@ -9385,8 +7645,6 @@ }, "node_modules/type-is": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.0.tgz", - "integrity": "sha512-gd0sGezQYCbWSbkZr75mln4YBidWUN60+devscpLF5mtRDUpiaTvKpBNrdaCvel1NdR2k6vclXybU5fBd2i+nw==", "license": "MIT", "dependencies": { "content-type": "^1.0.5", @@ -9399,8 +7657,6 @@ }, "node_modules/typescript": { "version": "5.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "devOptional": true, "license": "Apache-2.0", "bin": { @@ -9413,8 +7669,6 @@ }, "node_modules/typescript-eslint": { "version": "8.24.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.24.1.tgz", - "integrity": "sha512-cw3rEdzDqBs70TIcb0Gdzbt6h11BSs2pS0yaq7hDWDBtCCSei1pPSUXE9qUdQ/Wm9NgFg8mKtMt1b8fTHIl1jA==", "dev": true, "license": "MIT", "dependencies": { @@ -9436,15 +7690,10 @@ }, "node_modules/undici-types": { "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, "license": "MIT" }, "node_modules/unicorn-magic": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", - "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", "dev": true, "license": "MIT", "engines": { @@ -9456,8 +7705,7 @@ }, "node_modules/unique-filename": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "license": "ISC", "optional": true, "dependencies": { "unique-slug": "^2.0.0" @@ -9465,8 +7713,7 @@ }, "node_modules/unique-slug": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "license": "ISC", "optional": true, "dependencies": { "imurmurhash": "^0.1.4" @@ -9474,8 +7721,6 @@ }, "node_modules/universalify": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "license": "MIT", "engines": { "node": ">= 10.0.0" @@ -9483,8 +7728,6 @@ }, "node_modules/unpipe": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -9492,8 +7735,6 @@ }, "node_modules/update-browserslist-db": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz", - "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==", "dev": true, "funding": [ { @@ -9523,8 +7764,6 @@ }, "node_modules/uri-js": { "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -9533,14 +7772,10 @@ }, "node_modules/util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, "node_modules/utils-merge": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "license": "MIT", "engines": { "node": ">= 0.4.0" @@ -9548,27 +7783,22 @@ }, "node_modules/uuid": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", - "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], + "license": "MIT", "bin": { "uuid": "dist/esm/bin/uuid" } }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true, "license": "MIT" }, "node_modules/vary": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -9576,8 +7806,6 @@ }, "node_modules/vite": { "version": "6.1.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.1.1.tgz", - "integrity": "sha512-4GgM54XrwRfrOp297aIYspIti66k56v16ZnqHvrIM7mG+HjDlAwS7p+Srr7J6fGvEdOJ5JcQ/D9T7HhtdXDTzA==", "dev": true, "license": "MIT", "dependencies": { @@ -9648,8 +7876,6 @@ }, "node_modules/vite-hot-client": { "version": "0.2.4", - "resolved": "https://registry.npmjs.org/vite-hot-client/-/vite-hot-client-0.2.4.tgz", - "integrity": "sha512-a1nzURqO7DDmnXqabFOliz908FRmIppkBKsJthS8rbe8hBEXwEwe4C3Pp33Z1JoFCYfVL4kTOMLKk0ZZxREIeA==", "dev": true, "license": "MIT", "funding": { @@ -9661,8 +7887,6 @@ }, "node_modules/vite-node": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.6.tgz", - "integrity": "sha512-s51RzrTkXKJrhNbUzQRsarjmAae7VmMPAsRT7lppVpIg6mK3zGthP9Hgz0YQQKuNcF+Ii7DfYk3Fxz40jRmePw==", "dev": true, "license": "MIT", "dependencies": { @@ -9684,8 +7908,6 @@ }, "node_modules/vite-plugin-inspect": { "version": "0.8.9", - "resolved": "https://registry.npmjs.org/vite-plugin-inspect/-/vite-plugin-inspect-0.8.9.tgz", - "integrity": "sha512-22/8qn+LYonzibb1VeFZmISdVao5kC22jmEKm24vfFE8siEn47EpVcCLYMv6iKOYMJfjSvSJfueOwcFCkUnV3A==", "dev": true, "license": "MIT", "dependencies": { @@ -9716,8 +7938,6 @@ }, "node_modules/vite-plugin-vue-devtools": { "version": "7.7.2", - "resolved": "https://registry.npmjs.org/vite-plugin-vue-devtools/-/vite-plugin-vue-devtools-7.7.2.tgz", - "integrity": "sha512-5V0UijQWiSBj32blkyPEqIbzc6HO9c1bwnBhx+ay2dzU0FakH+qMdNUT8nF9BvDE+i6I1U8CqCuJiO20vKEdQw==", "dev": true, "license": "MIT", "dependencies": { @@ -9738,8 +7958,6 @@ }, "node_modules/vite-plugin-vue-inspector": { "version": "5.3.1", - "resolved": "https://registry.npmjs.org/vite-plugin-vue-inspector/-/vite-plugin-vue-inspector-5.3.1.tgz", - "integrity": "sha512-cBk172kZKTdvGpJuzCCLg8lJ909wopwsu3Ve9FsL1XsnLBiRT9U3MePcqrgGHgCX2ZgkqZmAGR8taxw+TV6s7A==", "dev": true, "license": "MIT", "dependencies": { @@ -9757,282 +7975,8 @@ "vite": "^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0" } }, - "node_modules/vite/node_modules/@esbuild/aix-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", - "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", - "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", - "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", - "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", - "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", - "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", - "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", - "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", - "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", - "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", - "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", - "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", - "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", - "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", - "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", - "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, "node_modules/vite/node_modules/@esbuild/linux-x64": { "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", - "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", "cpu": [ "x64" ], @@ -10046,146 +7990,8 @@ "node": ">=18" } }, - "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", - "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", - "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", - "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", - "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", - "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", - "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", - "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", - "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, "node_modules/vite/node_modules/esbuild": { "version": "0.24.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", - "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -10225,8 +8031,6 @@ }, "node_modules/vitest": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.6.tgz", - "integrity": "sha512-/iL1Sc5VeDZKPDe58oGK4HUFLhw6b5XdY1MYawjuSaDA4sEfYlY9HnS6aCEG26fX+MgUi7MwlduTBHHAI/OvMA==", "dev": true, "license": "MIT", "dependencies": { @@ -10295,15 +8099,11 @@ }, "node_modules/vscode-uri": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", - "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", "dev": true, "license": "MIT" }, "node_modules/vue": { "version": "3.5.13", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz", - "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==", "license": "MIT", "dependencies": { "@vue/compiler-dom": "3.5.13", @@ -10323,15 +8123,11 @@ }, "node_modules/vue-component-type-helpers": { "version": "2.2.2", - "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.2.2.tgz", - "integrity": "sha512-6lLY+n2xz2kCYshl59mL6gy8OUUTmkscmDFMO8i7Lj+QKwgnIFUZmM1i/iTYObtrczZVdw7UakPqDTGwVSGaRg==", "dev": true, "license": "MIT" }, "node_modules/vue-eslint-parser": { "version": "9.4.3", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz", - "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==", "dev": true, "license": "MIT", "dependencies": { @@ -10355,8 +8151,6 @@ }, "node_modules/vue-eslint-parser/node_modules/eslint-scope": { "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -10372,8 +8166,6 @@ }, "node_modules/vue-eslint-parser/node_modules/espree": { "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -10390,8 +8182,6 @@ }, "node_modules/vue-i18n": { "version": "10.0.5", - "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-10.0.5.tgz", - "integrity": "sha512-9/gmDlCblz3i8ypu/afiIc/SUIfTTE1mr0mZhb9pk70xo2csHAM9mp2gdQ3KD2O0AM3Hz/5ypb+FycTj/lHlPQ==", "license": "MIT", "dependencies": { "@intlify/core-base": "10.0.5", @@ -10410,8 +8200,6 @@ }, "node_modules/vue-router": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.0.tgz", - "integrity": "sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==", "license": "MIT", "dependencies": { "@vue/devtools-api": "^6.6.4" @@ -10425,8 +8213,6 @@ }, "node_modules/vue-tsc": { "version": "2.2.2", - "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.2.2.tgz", - "integrity": "sha512-1icPKkxAA5KTAaSwg0wVWdE48EdsH8fgvcbAiqojP4jXKl6LEM3soiW1aG/zrWrFt8Mw1ncG2vG1PvpZpVfehA==", "dev": true, "license": "MIT", "dependencies": { @@ -10441,9 +8227,7 @@ } }, "node_modules/vuetify": { - "version": "3.7.13", - "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.7.13.tgz", - "integrity": "sha512-4+RuQU+zLtXhlN2eZUpKXums9ftzUzhMeiNEJvvJY4XdOzVwUCth2dTnEZkSF6EKdLHk3WhtRk0cIWXZxpBvcw==", + "version": "3.7.12", "license": "MIT", "engines": { "node": "^12.20 || >=14.13" @@ -10472,8 +8256,6 @@ }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", "dev": true, "license": "MIT", "dependencies": { @@ -10485,8 +8267,6 @@ }, "node_modules/w3c-xmlserializer/node_modules/xml-name-validator": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", "dev": true, "license": "Apache-2.0", "engines": { @@ -10495,8 +8275,6 @@ }, "node_modules/webidl-conversions": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -10505,8 +8283,6 @@ }, "node_modules/whatwg-encoding": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10518,8 +8294,6 @@ }, "node_modules/whatwg-encoding/node_modules/iconv-lite": { "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "license": "MIT", "dependencies": { @@ -10531,8 +8305,6 @@ }, "node_modules/whatwg-mimetype": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", "dev": true, "license": "MIT", "engines": { @@ -10541,8 +8313,6 @@ }, "node_modules/whatwg-url": { "version": "14.1.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.1.tgz", - "integrity": "sha512-mDGf9diDad/giZ/Sm9Xi2YcyzaFpbdLpJPr+E9fSkyQ7KpQD4SdFcugkRQYzhmfI4KeV4Qpnn2sKPdo+kmsgRQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10555,8 +8325,6 @@ }, "node_modules/which": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "devOptional": true, "license": "ISC", "dependencies": { @@ -10571,8 +8339,6 @@ }, "node_modules/why-is-node-running": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, "license": "MIT", "dependencies": { @@ -10588,8 +8354,7 @@ }, "node_modules/wide-align": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", "optional": true, "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" @@ -10597,8 +8362,7 @@ }, "node_modules/wide-align/node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", "optional": true, "engines": { "node": ">=8" @@ -10606,14 +8370,12 @@ }, "node_modules/wide-align/node_modules/emoji-regex": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT", "optional": true }, "node_modules/wide-align/node_modules/string-width": { "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "optional": true, "dependencies": { "emoji-regex": "^8.0.0", @@ -10626,8 +8388,7 @@ }, "node_modules/wide-align/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "optional": true, "dependencies": { "ansi-regex": "^5.0.1" @@ -10638,8 +8399,6 @@ }, "node_modules/word-wrap": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", "engines": { @@ -10647,18 +8406,16 @@ } }, "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "version": "8.1.0", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -10667,8 +8424,6 @@ "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", "dependencies": { @@ -10683,16 +8438,60 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, "node_modules/ws": { "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, "license": "MIT", "engines": { @@ -10713,8 +8512,6 @@ }, "node_modules/xml-name-validator": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -10723,15 +8520,11 @@ }, "node_modules/xmlchars": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true, "license": "MIT" }, "node_modules/xtend": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "license": "MIT", "engines": { "node": ">=0.4" @@ -10739,8 +8532,6 @@ }, "node_modules/y18n": { "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, "license": "ISC", "engines": { @@ -10749,15 +8540,11 @@ }, "node_modules/yallist": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, "license": "ISC" }, "node_modules/yargs": { "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "license": "MIT", "dependencies": { @@ -10775,18 +8562,51 @@ }, "node_modules/yargs-parser": { "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, "license": "ISC", "engines": { "node": ">=12" } }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yn": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, "license": "MIT", "engines": { @@ -10795,8 +8615,6 @@ }, "node_modules/yocto-queue": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "license": "MIT", "engines": { @@ -10808,8 +8626,6 @@ }, "node_modules/yoctocolors": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.1.tgz", - "integrity": "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==", "dev": true, "license": "MIT", "engines": { From 054e761baa500ac9a79e4efe58e549ccbaeb0ab9 Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Sat, 1 Mar 2025 23:47:32 +0100 Subject: [PATCH 025/180] feat(backend): Generic authentication checks. Added support for deciding based on any predicate about the current AuthenticationInfo whether or not a request will be accepted. --- backend/src/middleware/auth/auth.ts | 78 ++++++++++++++----- .../middleware/auth/authentication-info.ts | 11 +++ 2 files changed, 71 insertions(+), 18 deletions(-) create mode 100644 backend/src/middleware/auth/authentication-info.ts diff --git a/backend/src/middleware/auth/auth.ts b/backend/src/middleware/auth/auth.ts index 82f1b23f..ec097fd5 100644 --- a/backend/src/middleware/auth/auth.ts +++ b/backend/src/middleware/auth/auth.ts @@ -5,6 +5,7 @@ import jwksClient from 'jwks-rsa'; import * as express from "express"; import * as jwt from "jsonwebtoken"; import {AuthenticatedRequest} from "./authenticated-request.js"; +import {AuthenticationInfo} from "./authentication-info"; function createJwksClient(uri: string): jwksClient.JwksClient { return jwksClient({ @@ -25,6 +26,9 @@ const idpConfigs = { } }; +/** + * Express middleware which verifies the JWT Bearer token if one is given in the request. + */ export const authenticateUser = expressjwt({ secret: async (_: express.Request, token: jwt.Jwt | undefined) => { if (!token?.payload || !(token.payload as JwtPayload).iss) { @@ -49,27 +53,65 @@ export const authenticateUser = expressjwt({ credentialsRequired: false }); -const authorizeRole = (studentsAllowed: boolean, teachersAllowed: boolean) => { +/** + * Get an object with information about the authenticated user from a given authenticated request. + */ +function getAuthenticationInfo(req: AuthenticatedRequest): AuthenticationInfo | undefined { + if (!req.auth) { + return; + } + + let issuer = req.auth.issuer; + let accountType: "student" | "teacher"; + + if (issuer === idpConfigs.student.issuer) { + accountType = "student"; + } else if (issuer === idpConfigs.teacher.issuer) { + accountType = "teacher"; + } else { + return; + } + + return { + accountType: accountType, + username: req.auth["preferred_username"]!, + name: req.auth["name"], + firstName: req.auth["given_name"], + lastName: req.auth["family_name"], + email: req.auth["email"], + } +} + +/** + * Middleware which rejects unauthenticated users (with HTTP 401) and authenticated users which do not fulfill + * the given access condition. + * @param accessCondition Predicate over the current AuthenticationInfo. Access is only granted when this evaluates + * to true. + */ +const authorize = (accessCondition: (auth: AuthenticationInfo) => boolean) => { return (req: AuthenticatedRequest, res: express.Response, next: express.NextFunction): void => { - if (!req.auth) { + let authInfo = getAuthenticationInfo(req); + if (!authInfo) { res.status(401).json({ message: "Unauthorized" }); - return; + } else if (!accessCondition(authInfo)) { + res.status(403).json({ message: "Forbidden" }); + } else { + next(); } + } +} - const issuer = req.auth.iss; - if (issuer === idpConfigs.student.issuer && !studentsAllowed) { - res.status(403).json({ message: "Students not allowed" }); - return; - } - if (issuer === idpConfigs.teacher.issuer && !teachersAllowed) { - res.status(403).json({ message: "Teachers not allowed" }); - return; - } +/** + * Middleware which rejects all unauthenticated users, but accepts all authenticated users. + */ +export const authenticatedOnly = authorize(_ => true); - next(); // User is allowed - }; -}; +/** + * Middleware which rejects requests from unauthenticated users or users that aren't students. + */ +export const studentsOnly = authorize(auth => auth.accountType === "student"); -export const authenticatedOnly = authorizeRole(true, true); -export const studentsOnly = authorizeRole(true, false); -export const teachersOnly = authorizeRole(false, true); +/** + * Middleware which rejects requests from unauthenticated users or users that aren't teachers. + */ +export const teachersOnly = authorize(auth => auth.accountType === "teacher"); diff --git a/backend/src/middleware/auth/authentication-info.ts b/backend/src/middleware/auth/authentication-info.ts new file mode 100644 index 00000000..6711edd0 --- /dev/null +++ b/backend/src/middleware/auth/authentication-info.ts @@ -0,0 +1,11 @@ +/** + * Object with information about the user who is currently logged in. + */ +export type AuthenticationInfo = { + accountType: "student" | "teacher", + username: string, + name?: string, + firstName?: string, + lastName?: string, + email?: string +}; From 69ba8c9567df56fc2871f4a88a416c8b0e1cc319 Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Sun, 2 Mar 2025 01:24:49 +0100 Subject: [PATCH 026/180] feat(backend): Generic authentication checks. Added support for deciding based on any predicate about the current AuthenticationInfo whether or not a request will be accepted. --- backend/src/middleware/auth/auth.ts | 40 ++++++++++++------- .../middleware/auth/authenticated-request.ts | 5 ++- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/backend/src/middleware/auth/auth.ts b/backend/src/middleware/auth/auth.ts index ec097fd5..0bf63e3d 100644 --- a/backend/src/middleware/auth/auth.ts +++ b/backend/src/middleware/auth/auth.ts @@ -29,7 +29,7 @@ const idpConfigs = { /** * Express middleware which verifies the JWT Bearer token if one is given in the request. */ -export const authenticateUser = expressjwt({ +const verifyJwtToken = expressjwt({ secret: async (_: express.Request, token: jwt.Jwt | undefined) => { if (!token?.payload || !(token.payload as JwtPayload).iss) { throw new Error("Invalid token"); @@ -50,18 +50,19 @@ export const authenticateUser = expressjwt({ }, audience: getEnvVar(EnvVars.IdpAudience), algorithms: ["RS256"], - credentialsRequired: false + credentialsRequired: false, + requestProperty: "jwtPayload" }); /** * Get an object with information about the authenticated user from a given authenticated request. */ function getAuthenticationInfo(req: AuthenticatedRequest): AuthenticationInfo | undefined { - if (!req.auth) { + console.log("hi"); + if (!req.jwtPayload) { return; } - - let issuer = req.auth.issuer; + let issuer = req.jwtPayload.iss; let accountType: "student" | "teacher"; if (issuer === idpConfigs.student.issuer) { @@ -71,29 +72,38 @@ function getAuthenticationInfo(req: AuthenticatedRequest): AuthenticationInfo | } else { return; } - return { accountType: accountType, - username: req.auth["preferred_username"]!, - name: req.auth["name"], - firstName: req.auth["given_name"], - lastName: req.auth["family_name"], - email: req.auth["email"], + username: req.jwtPayload["preferred_username"]!, + name: req.jwtPayload["name"], + firstName: req.jwtPayload["given_name"], + lastName: req.jwtPayload["family_name"], + email: req.jwtPayload["email"], } } +/** + * Add the AuthenticationInfo object with the information about the current authentication to the request in order + * to avoid that the routers have to deal with the JWT token. + */ +const addAuthenticationInfo = (req: AuthenticatedRequest, res: express.Response, next: express.NextFunction) => { + req.auth = getAuthenticationInfo(req); + next(); +}; + +export const authenticateUser = [verifyJwtToken, addAuthenticationInfo]; + /** * Middleware which rejects unauthenticated users (with HTTP 401) and authenticated users which do not fulfill * the given access condition. * @param accessCondition Predicate over the current AuthenticationInfo. Access is only granted when this evaluates * to true. */ -const authorize = (accessCondition: (auth: AuthenticationInfo) => boolean) => { +export const authorize = (accessCondition: (auth: AuthenticationInfo) => boolean) => { return (req: AuthenticatedRequest, res: express.Response, next: express.NextFunction): void => { - let authInfo = getAuthenticationInfo(req); - if (!authInfo) { + if (!req.auth) { res.status(401).json({ message: "Unauthorized" }); - } else if (!accessCondition(authInfo)) { + } else if (!accessCondition(req.auth)) { res.status(403).json({ message: "Forbidden" }); } else { next(); diff --git a/backend/src/middleware/auth/authenticated-request.ts b/backend/src/middleware/auth/authenticated-request.ts index 9b33de6f..b29cfbac 100644 --- a/backend/src/middleware/auth/authenticated-request.ts +++ b/backend/src/middleware/auth/authenticated-request.ts @@ -1,6 +1,9 @@ import { Request } from "express"; import { JwtPayload } from "jsonwebtoken"; +import {AuthenticationInfo} from "./authentication-info"; export interface AuthenticatedRequest extends Request { - auth?: JwtPayload; // Optional, as req.auth might be undefined if authentication is optional + // Properties are optional since the user is not necessarily authenticated. + jwtPayload?: JwtPayload; + auth?: AuthenticationInfo; } From 4f201a12530e83aabe0ee370e3a63234622adee1 Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Sun, 2 Mar 2025 01:25:57 +0100 Subject: [PATCH 027/180] chore(backend): Automatische import van testdata in Keycloack. Zie idp/README.md voor meer informatie erover wat de testdata inhoudt. --- docker-compose.yml | 15 +- idp/README.md | 7 + idp/student-realm.json | 2062 ++++++++++++++++++++++++++++++++++++++++ idp/teacher-realm.json | 2060 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 4141 insertions(+), 3 deletions(-) create mode 100644 idp/README.md create mode 100644 idp/student-realm.json create mode 100644 idp/teacher-realm.json diff --git a/docker-compose.yml b/docker-compose.yml index df906ba4..18249f52 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,12 +11,14 @@ services: - postgres_data:/var/lib/postgresql/data idp: # Bron: https://medium.com/@fingervinicius/easy-running-keycloak-with-docker-compose-b0d7a4ee2358 image: quay.io/keycloak/keycloak:latest + volumes: + - ./idp:/opt/keycloak/data/import environment: KC_HOSTNAME: localhost KC_HOSTNAME_PORT: 7080 KC_HOSTNAME_STRICT_BACKCHANNEL: "true" - KEYCLOAK_ADMIN: admin - KEYCLOAK_ADMIN_PASSWORD: admin + KC_BOOTSTRAP_ADMIN_USERNAME: admin + KC_BOOTSTRAP_ADMIN_PASSWORD: admin KC_HEALTH_ENABLED: "true" KC_LOG_LEVEL: info healthcheck: @@ -24,9 +26,16 @@ services: interval: 15s timeout: 2s retries: 15 - command: ["start-dev", "--http-port", "7080", "--https-port", "7443"] + command: [ + "start-dev", + "--http-port", "7080", + "--https-port", "7443", + "--import-realm" + ] ports: - "7080:7080" - "7443:7443" + depends_on: + - db volumes: postgres_data: diff --git a/idp/README.md b/idp/README.md new file mode 100644 index 00000000..3f3fd4ff --- /dev/null +++ b/idp/README.md @@ -0,0 +1,7 @@ +# Testdata in de IDP +De IDP in `docker-compose.yml` is zo geconfigureerd dat hij automatisch bij het starten een testconfiguratie inlaadt. Deze houdt in: +* Een realm `student` die de IDP voor leerlingen representeert. + * Hierin de gebruiker met username `testleerling1`, wachtwoord `password`. +* Een realm `teacher` die de IDP voor leerkrachten representeert. + * Hierin de gebruiker met username `testleerkracht1`, wachtwoord `password`. +* De admin-account (in de realm `master`) heeft username `admin` en wachtwoord `admin`. diff --git a/idp/student-realm.json b/idp/student-realm.json new file mode 100644 index 00000000..57ff2dd2 --- /dev/null +++ b/idp/student-realm.json @@ -0,0 +1,2062 @@ +{ + "id" : "08a7ab0a-d483-4103-a781-76013864bf50", + "realm" : "student", + "notBefore" : 0, + "defaultSignatureAlgorithm" : "RS256", + "revokeRefreshToken" : false, + "refreshTokenMaxReuse" : 0, + "accessTokenLifespan" : 300, + "accessTokenLifespanForImplicitFlow" : 900, + "ssoSessionIdleTimeout" : 1800, + "ssoSessionMaxLifespan" : 36000, + "ssoSessionIdleTimeoutRememberMe" : 0, + "ssoSessionMaxLifespanRememberMe" : 0, + "offlineSessionIdleTimeout" : 2592000, + "offlineSessionMaxLifespanEnabled" : false, + "offlineSessionMaxLifespan" : 5184000, + "clientSessionIdleTimeout" : 0, + "clientSessionMaxLifespan" : 0, + "clientOfflineSessionIdleTimeout" : 0, + "clientOfflineSessionMaxLifespan" : 0, + "accessCodeLifespan" : 60, + "accessCodeLifespanUserAction" : 300, + "accessCodeLifespanLogin" : 1800, + "actionTokenGeneratedByAdminLifespan" : 43200, + "actionTokenGeneratedByUserLifespan" : 300, + "oauth2DeviceCodeLifespan" : 600, + "oauth2DevicePollingInterval" : 5, + "enabled" : true, + "sslRequired" : "external", + "registrationAllowed" : false, + "registrationEmailAsUsername" : false, + "rememberMe" : false, + "verifyEmail" : false, + "loginWithEmailAllowed" : true, + "duplicateEmailsAllowed" : false, + "resetPasswordAllowed" : false, + "editUsernameAllowed" : false, + "bruteForceProtected" : false, + "permanentLockout" : false, + "maxTemporaryLockouts" : 0, + "bruteForceStrategy" : "MULTIPLE", + "maxFailureWaitSeconds" : 900, + "minimumQuickLoginWaitSeconds" : 60, + "waitIncrementSeconds" : 60, + "quickLoginCheckMilliSeconds" : 1000, + "maxDeltaTimeSeconds" : 43200, + "failureFactor" : 30, + "roles" : { + "realm" : [ { + "id" : "a0bb00f5-0b3a-4d57-a3fc-a3f93cbe3427", + "name" : "offline_access", + "description" : "${role_offline-access}", + "composite" : false, + "clientRole" : false, + "containerId" : "08a7ab0a-d483-4103-a781-76013864bf50", + "attributes" : { } + }, { + "id" : "b3bf9566-098c-4167-9cce-f64c720ca511", + "name" : "default-roles-student", + "description" : "${role_default-roles}", + "composite" : true, + "composites" : { + "realm" : [ "offline_access", "uma_authorization" ], + "client" : { + "account" : [ "manage-account", "view-profile" ] + } + }, + "clientRole" : false, + "containerId" : "08a7ab0a-d483-4103-a781-76013864bf50", + "attributes" : { } + }, { + "id" : "6d044f54-8ff3-4223-9e8c-771882da7a3f", + "name" : "uma_authorization", + "description" : "${role_uma_authorization}", + "composite" : false, + "clientRole" : false, + "containerId" : "08a7ab0a-d483-4103-a781-76013864bf50", + "attributes" : { } + } ], + "client" : { + "realm-management" : [ { + "id" : "f125e557-2427-4eeb-95c5-b3dadf35f9c7", + "name" : "manage-authorization", + "description" : "${role_manage-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes" : { } + }, { + "id" : "33c7285a-7308-4752-acad-1fe59bf1c81a", + "name" : "manage-identity-providers", + "description" : "${role_manage-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes" : { } + }, { + "id" : "31fb3621-62c7-43c8-af98-a4add3470fcc", + "name" : "query-clients", + "description" : "${role_query-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes" : { } + }, { + "id" : "e077c3c3-d573-494f-9cf8-34eca6603fc6", + "name" : "realm-admin", + "description" : "${role_realm-admin}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "manage-authorization", "query-clients", "manage-identity-providers", "create-client", "view-users", "view-authorization", "query-users", "manage-users", "view-identity-providers", "impersonation", "manage-realm", "view-events", "view-clients", "manage-events", "manage-clients", "view-realm", "query-groups", "query-realms" ] + } + }, + "clientRole" : true, + "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes" : { } + }, { + "id" : "8bbe59b1-7693-4274-bdde-c08f94ec3187", + "name" : "create-client", + "description" : "${role_create-client}", + "composite" : false, + "clientRole" : true, + "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes" : { } + }, { + "id" : "0533162d-7dac-4ebf-87a2-7f72dad79d53", + "name" : "view-users", + "description" : "${role_view-users}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-groups", "query-users" ] + } + }, + "clientRole" : true, + "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes" : { } + }, { + "id" : "d4b32078-67b4-4aa8-8ddf-01a820e7b64a", + "name" : "view-authorization", + "description" : "${role_view-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes" : { } + }, { + "id" : "2a48ab18-b710-41e7-8b8c-67a5cd6af685", + "name" : "query-users", + "description" : "${role_query-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes" : { } + }, { + "id" : "d71d575f-3f21-4f4a-b9e0-2628352aac8d", + "name" : "manage-users", + "description" : "${role_manage-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes" : { } + }, { + "id" : "7d3cd659-4ddd-45cd-8186-210431a25bbd", + "name" : "impersonation", + "description" : "${role_impersonation}", + "composite" : false, + "clientRole" : true, + "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes" : { } + }, { + "id" : "3dbd18ca-11dc-463d-bf8e-e7d80928a90d", + "name" : "view-identity-providers", + "description" : "${role_view-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes" : { } + }, { + "id" : "d4a6ef1e-bf84-4bd6-8763-1b0c9997c109", + "name" : "manage-realm", + "description" : "${role_manage-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes" : { } + }, { + "id" : "f0eab8d7-0570-44d3-94d0-2a43906d9f09", + "name" : "view-events", + "description" : "${role_view-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes" : { } + }, { + "id" : "0a24b91f-ef4a-4f4b-a753-1286dd59df2b", + "name" : "view-clients", + "description" : "${role_view-clients}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-clients" ] + } + }, + "clientRole" : true, + "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes" : { } + }, { + "id" : "b307485c-8840-4c39-ba81-fb840fa404d1", + "name" : "manage-events", + "description" : "${role_manage-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes" : { } + }, { + "id" : "3719a5ed-be30-4d2c-93f5-cc6e6c0e792e", + "name" : "manage-clients", + "description" : "${role_manage-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes" : { } + }, { + "id" : "d4b13416-9f5e-42fb-bfdd-6489093922da", + "name" : "view-realm", + "description" : "${role_view-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes" : { } + }, { + "id" : "15ac861b-5440-4fe8-9f7d-857d75ec481d", + "name" : "query-groups", + "description" : "${role_query-groups}", + "composite" : false, + "clientRole" : true, + "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes" : { } + }, { + "id" : "f05a8e4d-90ea-41f6-887b-0b6b1ecb9cd9", + "name" : "query-realms", + "description" : "${role_query-realms}", + "composite" : false, + "clientRole" : true, + "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes" : { } + } ], + "dwengo" : [ ], + "security-admin-console" : [ ], + "admin-cli" : [ ], + "account-console" : [ ], + "broker" : [ { + "id" : "da1edd82-7479-4e9d-ad66-9a4cf739e828", + "name" : "read-token", + "description" : "${role_read-token}", + "composite" : false, + "clientRole" : true, + "containerId" : "befe3d72-8102-49a6-8268-bce6def58159", + "attributes" : { } + } ], + "account" : [ { + "id" : "5a3da53d-235b-4d12-b8ec-1573b13ebafc", + "name" : "view-consent", + "description" : "${role_view-consent}", + "composite" : false, + "clientRole" : true, + "containerId" : "b3a22454-d780-4093-8333-9be6f6cd5855", + "attributes" : { } + }, { + "id" : "cbc0c1d4-487b-488c-8566-1d4537212de8", + "name" : "manage-account-links", + "description" : "${role_manage-account-links}", + "composite" : false, + "clientRole" : true, + "containerId" : "b3a22454-d780-4093-8333-9be6f6cd5855", + "attributes" : { } + }, { + "id" : "79b0ed8f-bf10-4b01-bb2c-e7a58d57c798", + "name" : "delete-account", + "description" : "${role_delete-account}", + "composite" : false, + "clientRole" : true, + "containerId" : "b3a22454-d780-4093-8333-9be6f6cd5855", + "attributes" : { } + }, { + "id" : "b6aa748e-0fb0-4fa6-a0d1-3ea37c870467", + "name" : "manage-account", + "description" : "${role_manage-account}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "manage-account-links" ] + } + }, + "clientRole" : true, + "containerId" : "b3a22454-d780-4093-8333-9be6f6cd5855", + "attributes" : { } + }, { + "id" : "ddaea6cd-ede8-49f7-9746-3a3a02fdeca5", + "name" : "view-profile", + "description" : "${role_view-profile}", + "composite" : false, + "clientRole" : true, + "containerId" : "b3a22454-d780-4093-8333-9be6f6cd5855", + "attributes" : { } + }, { + "id" : "061b2038-b415-4a45-89ec-7141004c0151", + "name" : "view-applications", + "description" : "${role_view-applications}", + "composite" : false, + "clientRole" : true, + "containerId" : "b3a22454-d780-4093-8333-9be6f6cd5855", + "attributes" : { } + }, { + "id" : "95972aa1-6666-421c-8596-a91eee54b0e8", + "name" : "view-groups", + "description" : "${role_view-groups}", + "composite" : false, + "clientRole" : true, + "containerId" : "b3a22454-d780-4093-8333-9be6f6cd5855", + "attributes" : { } + }, { + "id" : "1cf27d94-d88d-42d3-b8f3-ede1f127ac45", + "name" : "manage-consent", + "description" : "${role_manage-consent}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "view-consent" ] + } + }, + "clientRole" : true, + "containerId" : "b3a22454-d780-4093-8333-9be6f6cd5855", + "attributes" : { } + } ] + } + }, + "groups" : [ ], + "defaultRole" : { + "id" : "b3bf9566-098c-4167-9cce-f64c720ca511", + "name" : "default-roles-student", + "description" : "${role_default-roles}", + "composite" : true, + "clientRole" : false, + "containerId" : "08a7ab0a-d483-4103-a781-76013864bf50" + }, + "requiredCredentials" : [ "password" ], + "otpPolicyType" : "totp", + "otpPolicyAlgorithm" : "HmacSHA1", + "otpPolicyInitialCounter" : 0, + "otpPolicyDigits" : 6, + "otpPolicyLookAheadWindow" : 1, + "otpPolicyPeriod" : 30, + "otpPolicyCodeReusable" : false, + "otpSupportedApplications" : [ "totpAppFreeOTPName", "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName" ], + "localizationTexts" : { }, + "webAuthnPolicyRpEntityName" : "keycloak", + "webAuthnPolicySignatureAlgorithms" : [ "ES256", "RS256" ], + "webAuthnPolicyRpId" : "", + "webAuthnPolicyAttestationConveyancePreference" : "not specified", + "webAuthnPolicyAuthenticatorAttachment" : "not specified", + "webAuthnPolicyRequireResidentKey" : "not specified", + "webAuthnPolicyUserVerificationRequirement" : "not specified", + "webAuthnPolicyCreateTimeout" : 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister" : false, + "webAuthnPolicyAcceptableAaguids" : [ ], + "webAuthnPolicyExtraOrigins" : [ ], + "webAuthnPolicyPasswordlessRpEntityName" : "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms" : [ "ES256", "RS256" ], + "webAuthnPolicyPasswordlessRpId" : "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference" : "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment" : "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey" : "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement" : "not specified", + "webAuthnPolicyPasswordlessCreateTimeout" : 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false, + "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ], + "webAuthnPolicyPasswordlessExtraOrigins" : [ ], + "users" : [ { + "id" : "79e9a395-d7e4-48c9-a06e-702435bae290", + "username" : "testleerling1", + "firstName" : "Gerald", + "lastName" : "Schmittinger", + "email" : "Gerald.Schmittinger@UGent.be", + "emailVerified" : false, + "createdTimestamp" : 1740858528405, + "enabled" : true, + "totp" : false, + "credentials" : [ { + "id" : "c31a708f-8614-4144-a25f-3e976c9035ce", + "type" : "password", + "userLabel" : "My password", + "createdDate" : 1740858548515, + "secretData" : "{\"value\":\"yDKIAbZPuVXBGk4zjiqE/YFcPDm1vjXLwTrPUrvMhXY=\",\"salt\":\"tYvjd4mhV2UWeOUssK01Cw==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-student" ], + "notBefore" : 0, + "groups" : [ ] + } ], + "scopeMappings" : [ { + "clientScope" : "offline_access", + "roles" : [ "offline_access" ] + } ], + "clientScopeMappings" : { + "account" : [ { + "client" : "account-console", + "roles" : [ "manage-account", "view-groups" ] + } ] + }, + "clients" : [ { + "id" : "b3a22454-d780-4093-8333-9be6f6cd5855", + "clientId" : "account", + "name" : "${client_account}", + "rootUrl" : "${authBaseUrl}", + "baseUrl" : "/realms/student/account/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/realms/student/account/*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "realm_client" : "false", + "post.logout.redirect.uris" : "+" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] + }, { + "id" : "854c221b-630c-4cc3-9365-bd254246dd69", + "clientId" : "account-console", + "name" : "${client_account-console}", + "rootUrl" : "${authBaseUrl}", + "baseUrl" : "/realms/student/account/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/realms/student/account/*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "realm_client" : "false", + "post.logout.redirect.uris" : "+", + "pkce.code.challenge.method" : "S256" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "protocolMappers" : [ { + "id" : "f33b40fe-bb9e-4254-ada9-f98dd203641b", + "name" : "audience resolve", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-audience-resolve-mapper", + "consentRequired" : false, + "config" : { } + } ], + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] + }, { + "id" : "9449aa8b-d5cc-4b9f-bb01-be1e5a896f2f", + "clientId" : "admin-cli", + "name" : "${client_admin-cli}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : false, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "realm_client" : "false", + "client.use.lightweight.access.token.enabled" : "true" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : true, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] + }, { + "id" : "befe3d72-8102-49a6-8268-bce6def58159", + "clientId" : "broker", + "name" : "${client_broker}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : true, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "realm_client" : "true" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] + }, { + "id" : "714243ae-72cc-4c26-842a-047357b5919a", + "clientId" : "dwengo", + "name" : "Dwengo", + "description" : "", + "rootUrl" : "http://localhost:3000", + "adminUrl" : "http://localhost:3000", + "baseUrl" : "/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-jwt", + "redirectUris" : [ "urn:ietf:wg:oauth:2.0:oob", "http://localhost:3000/*", "http://localhost:3000" ], + "webOrigins" : [ "+" ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : true, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : true, + "protocol" : "openid-connect", + "attributes" : { + "realm_client" : "false", + "oidc.ciba.grant.enabled" : "false", + "client.secret.creation.time" : "1740860818", + "backchannel.logout.session.required" : "true", + "token.endpoint.auth.signing.alg" : "RS256", + "post.logout.redirect.uris" : "+", + "frontchannel.logout.session.required" : "true", + "oauth2.device.authorization.grant.enabled" : "false", + "display.on.consent.screen" : "false", + "backchannel.logout.revoke.offline.tokens" : "false" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : true, + "nodeReRegistrationTimeout" : -1, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] + }, { + "id" : "0b06aaa3-717d-4a52-ab46-295a6571b642", + "clientId" : "realm-management", + "name" : "${client_realm-management}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : true, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "realm_client" : "true" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] + }, { + "id" : "dfc7248c-3794-4e3b-aed2-3ee553cd0feb", + "clientId" : "security-admin-console", + "name" : "${client_security-admin-console}", + "rootUrl" : "${authAdminUrl}", + "baseUrl" : "/admin/student/console/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/admin/student/console/*" ], + "webOrigins" : [ "+" ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "realm_client" : "false", + "client.use.lightweight.access.token.enabled" : "true", + "post.logout.redirect.uris" : "+", + "pkce.code.challenge.method" : "S256" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : true, + "nodeReRegistrationTimeout" : 0, + "protocolMappers" : [ { + "id" : "9e9ff295-30c9-43f1-a11a-773724709c07", + "name" : "locale", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "locale", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "locale", + "jsonType.label" : "String" + } + } ], + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] + } ], + "clientScopes" : [ { + "id" : "0721b27a-284f-4e6d-af70-b6f190ebdcd4", + "name" : "email", + "description" : "OpenID Connect built-in scope: email", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "consent.screen.text" : "${emailScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "d256bdc1-8983-41e0-b8fa-fcf45653045e", + "name" : "email verified", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "emailVerified", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "email_verified", + "jsonType.label" : "boolean" + } + }, { + "id" : "651c2415-db30-40ed-bdef-745b6ea744ed", + "name" : "email", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "email", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "email", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "573f6eea-7626-44fe-9855-50f15c3939ba", + "name" : "web-origins", + "description" : "OpenID Connect scope for add allowed web origins to the access token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "consent.screen.text" : "", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "3489c748-3cc7-4350-9351-2955fc7084ba", + "name" : "allowed web origins", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-allowed-origins-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "access.token.claim" : "true" + } + } ] + }, { + "id" : "00afe548-c677-4595-8478-16f752c2713a", + "name" : "offline_access", + "description" : "OpenID Connect built-in scope: offline_access", + "protocol" : "openid-connect", + "attributes" : { + "consent.screen.text" : "${offlineAccessScopeConsentText}", + "display.on.consent.screen" : "true" + } + }, { + "id" : "1448ed2b-ec1d-4bf4-a8b7-00cb85459289", + "name" : "address", + "description" : "OpenID Connect built-in scope: address", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "consent.screen.text" : "${addressScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "12d491b6-5d74-4168-ac5c-517ebc2f1de4", + "name" : "address", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-address-mapper", + "consentRequired" : false, + "config" : { + "user.attribute.formatted" : "formatted", + "user.attribute.country" : "country", + "introspection.token.claim" : "true", + "user.attribute.postal_code" : "postal_code", + "userinfo.token.claim" : "true", + "user.attribute.street" : "street", + "id.token.claim" : "true", + "user.attribute.region" : "region", + "access.token.claim" : "true", + "user.attribute.locality" : "locality" + } + } ] + }, { + "id" : "52223fb1-9651-4cdf-8317-a1301d4042f7", + "name" : "organization", + "description" : "Additional claims about the organization a subject belongs to", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "consent.screen.text" : "${organizationScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "dccc4214-ece6-4235-8119-ee8cb954c29a", + "name" : "organization", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-organization-membership-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "introspection.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "organization", + "jsonType.label" : "String", + "multivalued" : "true" + } + } ] + }, { + "id" : "8be22542-e327-4a25-8265-a34a29607d1b", + "name" : "service_account", + "description" : "Specific scope for a client enabled for service accounts", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "cf89064a-0af3-4a4b-a838-3528a8f4d780", + "name" : "Client IP Address", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientAddress", + "id.token.claim" : "true", + "introspection.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientAddress", + "jsonType.label" : "String" + } + }, { + "id" : "dc0f77e6-cc20-4c0a-baf3-f45046d749d1", + "name" : "Client ID", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "client_id", + "id.token.claim" : "true", + "introspection.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "client_id", + "jsonType.label" : "String" + } + }, { + "id" : "d63fd29a-3613-4529-a8e4-3a7d7e9f5802", + "name" : "Client Host", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientHost", + "id.token.claim" : "true", + "introspection.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientHost", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "d9079603-62b7-4680-9d01-950daae75d6b", + "name" : "saml_organization", + "description" : "Organization Membership", + "protocol" : "saml", + "attributes" : { + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "d826fc58-b006-49ad-93dc-a76700e800df", + "name" : "organization", + "protocol" : "saml", + "protocolMapper" : "saml-organization-membership-mapper", + "consentRequired" : false, + "config" : { } + } ] + }, { + "id" : "171d8267-87da-4a4b-9346-d901d470248b", + "name" : "phone", + "description" : "OpenID Connect built-in scope: phone", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "consent.screen.text" : "${phoneScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "f8bb18d4-af9d-49b0-a61f-cc81887870cd", + "name" : "phone number", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "phoneNumber", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "phone_number", + "jsonType.label" : "String" + } + }, { + "id" : "88a2c658-9b61-40a2-abd5-69c501286031", + "name" : "phone number verified", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "phoneNumberVerified", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "phone_number_verified", + "jsonType.label" : "boolean" + } + } ] + }, { + "id" : "ea3b84ac-a91f-4a3d-be4e-893e11eaf4a1", + "name" : "acr", + "description" : "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "152d66d4-524f-47f1-a592-be3a0c043a4f", + "name" : "acr loa level", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-acr-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "introspection.token.claim" : "true", + "access.token.claim" : "true" + } + } ] + }, { + "id" : "2fc1ad0d-1065-4196-8d1b-c61525c9425d", + "name" : "microprofile-jwt", + "description" : "Microprofile - JWT built-in scope", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "9d537486-f6bf-4856-91fc-ca3acaa78814", + "name" : "upn", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "username", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "upn", + "jsonType.label" : "String" + } + }, { + "id" : "55425438-4111-47a0-9a36-fec9dbbc6a8a", + "name" : "groups", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-realm-role-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "multivalued" : "true", + "user.attribute" : "foo", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "groups", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "0d186f4e-ef6d-4fbc-9593-081e0d5ad171", + "name" : "profile", + "description" : "OpenID Connect built-in scope: profile", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "consent.screen.text" : "${profileScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "bb8bb550-2db6-4631-97dc-1d115d0e3034", + "name" : "given name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "firstName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "given_name", + "jsonType.label" : "String" + } + }, { + "id" : "c942089b-2898-4052-a64d-85b61e27aaa4", + "name" : "username", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "username", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "preferred_username", + "jsonType.label" : "String" + } + }, { + "id" : "5ff3a9ca-7036-458c-b0dc-41216292d210", + "name" : "updated at", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "updatedAt", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "updated_at", + "jsonType.label" : "long" + } + }, { + "id" : "41f93d62-4074-4373-a270-9bdf1e298cb5", + "name" : "website", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "website", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "website", + "jsonType.label" : "String" + } + }, { + "id" : "ffec7d63-0f78-41ea-8023-6c7c64661b34", + "name" : "locale", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "locale", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "locale", + "jsonType.label" : "String" + } + }, { + "id" : "4a514ae7-d29f-4979-8df9-a97b36a81a96", + "name" : "profile", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "profile", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "profile", + "jsonType.label" : "String" + } + }, { + "id" : "286e349b-cb9f-41b1-b9dc-d787f13e9d99", + "name" : "nickname", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "nickname", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "nickname", + "jsonType.label" : "String" + } + }, { + "id" : "f5177603-55b1-4abe-aee6-b1e5a05e37f6", + "name" : "full name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-full-name-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "introspection.token.claim" : "true", + "access.token.claim" : "true", + "userinfo.token.claim" : "true" + } + }, { + "id" : "a31114d7-05fc-40c1-9ea8-6977f6f0bec5", + "name" : "zoneinfo", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "zoneinfo", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "zoneinfo", + "jsonType.label" : "String" + } + }, { + "id" : "8884be77-648d-4083-b0cf-57130162c8dc", + "name" : "gender", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "gender", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "gender", + "jsonType.label" : "String" + } + }, { + "id" : "61840434-c79f-455a-a914-117977197304", + "name" : "family name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "lastName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "family_name", + "jsonType.label" : "String" + } + }, { + "id" : "1f40ff0b-1664-4259-846b-ab707c76d33b", + "name" : "middle name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "middleName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "middle_name", + "jsonType.label" : "String" + } + }, { + "id" : "8534d400-8a81-4ae3-b51f-78b93e5a2045", + "name" : "picture", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "picture", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "picture", + "jsonType.label" : "String" + } + }, { + "id" : "82a0e240-0824-41b9-b6e8-856a72d1e930", + "name" : "birthdate", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "birthdate", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "birthdate", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "a5cedc85-d9e9-42e1-9ea3-ff37d21d5e27", + "name" : "role_list", + "description" : "SAML role list", + "protocol" : "saml", + "attributes" : { + "consent.screen.text" : "${samlRoleListScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "19009128-590f-4bc9-80de-c9ba4aae822d", + "name" : "role list", + "protocol" : "saml", + "protocolMapper" : "saml-role-list-mapper", + "consentRequired" : false, + "config" : { + "single" : "false", + "attribute.nameformat" : "Basic", + "attribute.name" : "Role" + } + } ] + }, { + "id" : "3b6bb88b-c833-4bb5-9bd0-95831aa2ad0d", + "name" : "basic", + "description" : "OpenID Connect scope for add all basic claims to the token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "ce925803-aec2-47cb-a3b9-4bef12c80367", + "name" : "sub", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-sub-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "access.token.claim" : "true" + } + }, { + "id" : "58729b3a-3816-460e-bf2e-d0d2206c1830", + "name" : "auth_time", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "AUTH_TIME", + "id.token.claim" : "true", + "introspection.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "auth_time", + "jsonType.label" : "long" + } + } ] + }, { + "id" : "7aa2d936-3edb-45e5-bae0-b4a618d06371", + "name" : "roles", + "description" : "OpenID Connect scope for add user roles to the access token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "consent.screen.text" : "${rolesScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "a9d1e8e2-ca10-4904-8a42-7708b0bfdefa", + "name" : "client roles", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-client-role-mapper", + "consentRequired" : false, + "config" : { + "user.attribute" : "foo", + "introspection.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "resource_access.${client_id}.roles", + "jsonType.label" : "String", + "multivalued" : "true" + } + }, { + "id" : "1f217073-ad43-483b-b0d5-f3ca4c74282f", + "name" : "realm roles", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-realm-role-mapper", + "consentRequired" : false, + "config" : { + "user.attribute" : "foo", + "introspection.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "realm_access.roles", + "jsonType.label" : "String", + "multivalued" : "true" + } + }, { + "id" : "61b0a069-8b67-4692-bcca-66a197b230eb", + "name" : "audience resolve", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-audience-resolve-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "access.token.claim" : "true" + } + } ] + } ], + "defaultDefaultClientScopes" : [ "role_list", "saml_organization", "profile", "email", "roles", "web-origins", "acr", "basic" ], + "defaultOptionalClientScopes" : [ "offline_access", "address", "phone", "microprofile-jwt", "organization" ], + "browserSecurityHeaders" : { + "contentSecurityPolicyReportOnly" : "", + "xContentTypeOptions" : "nosniff", + "referrerPolicy" : "no-referrer", + "xRobotsTag" : "none", + "xFrameOptions" : "SAMEORIGIN", + "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection" : "1; mode=block", + "strictTransportSecurity" : "max-age=31536000; includeSubDomains" + }, + "smtpServer" : { }, + "eventsEnabled" : false, + "eventsListeners" : [ "jboss-logging" ], + "enabledEventTypes" : [ ], + "adminEventsEnabled" : false, + "adminEventsDetailsEnabled" : false, + "identityProviders" : [ ], + "identityProviderMappers" : [ ], + "components" : { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ { + "id" : "9eac5531-7f25-493f-a721-6c5e65cd34c2", + "name" : "Max Clients Limit", + "providerId" : "max-clients", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "max-clients" : [ "200" ] + } + }, { + "id" : "d9319a22-4c67-4b08-822f-4162a1ee01bc", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ] + } + }, { + "id" : "21456c8e-7f6b-4e49-a3e1-bea7f900e2fb", + "name" : "Consent Required", + "providerId" : "consent-required", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "4872e99b-b55b-4e13-8a93-63e853289cac", + "name" : "Full Scope Disabled", + "providerId" : "scope", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "a118a194-09f5-435d-9d4b-363813413167", + "name" : "Trusted Hosts", + "providerId" : "trusted-hosts", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "host-sending-registration-request-must-match" : [ "true" ], + "client-uris-must-match" : [ "true" ] + } + }, { + "id" : "e32b1e26-6571-4b0c-a205-0fbb3de44384", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ] + } + }, { + "id" : "9dbe6752-9978-42a3-9210-9ec166140de2", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper", "saml-role-list-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper" ] + } + }, { + "id" : "7027b3f4-d877-4814-ac78-f1edb8eb89b0", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper", "saml-user-property-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper" ] + } + } ], + "org.keycloak.keys.KeyProvider" : [ { + "id" : "819cfc66-a997-4747-9d90-a7f0c09774bf", + "name" : "aes-generated", + "providerId" : "aes-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "eb74df73-3f34-457d-95c7-5ad909107703" ], + "secret" : [ "1K8IJiDODmotHJPStrXhtA" ], + "priority" : [ "100" ] + } + }, { + "id" : "299857cd-52a4-4981-8171-02e7d8f12960", + "name" : "rsa-generated", + "providerId" : "rsa-generated", + "subComponents" : { }, + "config" : { + "privateKey" : [ "MIIEpAIBAAKCAQEA1MRmAT/yImkVfPMBxC0QHdC4DQfuWUTjKeEku+gMI9jX5ChUzzzVugcvZWmxBNcvOz7p6R8EdPllZKIwFSH5WvQ1w1VIgQwIlYfpi/pknfftLd66MI2fXrQK19dRTeQRivEf39GTfBQ2Xc7y1q7zbMo5TVxATJ3DgPi13dYO7zVPpGTiQQeYiezlcBedyGe4cS1g6oBoaVif1QPY1Ni2vEjJhczNMGI408tIFws8G04Tlno814nT0ysdflUSGcRUku41NtfM9hr57LQ459sGYho8Pn11lDuiUWkomJv0y3GJ1wFBvQbDvI+6QvEdFu0GxShrlcORrNmj3BwOOLhB7wIDAQABAoIBAA6zrXq7oO8YxMfYANC97mWpBPa9jA42EN5VdNTZIXGeq7hTwxx4zynmEjPXPEih190nqUEXCBdPHl74SAtFyDWtN0PSkkp8euFePViTSj2SIpzvTX1KY+9G0JL+iVsw/bdUlwe/swm5WdJcmPIVr7NeO9xpGfZRVm+EgAieoHSN4Z7g20wLbVz1fya+6O5Hy+IGezamIA4tchk+4hyiVpSh2TcdjkJJZWOlHKPkwWU/MYQbJibuea5jLoWA39NIqV2l5GT0SoCbffGJNb9CMTTGmXoK5zNwHhG+M0a4eP1vbFDLaoDne86JySmTdv/WrTFFa3veelw2K8PHDybuB70CgYEA/gbxqLZYkJcEpqsjM/XcISFJ09icJLKl5r2l/Dm4Qq587QniQYribX/PPLfDhgVwPByQe3rccq9FoiILycTdIwgSMTsg5fzvbLJTqMAcl2r0zJgHVIDc6iXnytuE0FffKN0kSKL1C4d6n6vKoCGvOcZoXK5jxgzpY8lasvKxhCsCgYEA1mtr7CDYY3qPmTu4/Uz6cFgX8RDMZZ11AQQXNMsKHIu5C4xLeYmJMlpt0y4h52/NWRzh2svdw3SEZTCfP1WVC7StfP8KD8QdwVkQlY5EGkiz9uRtEgwk8chkOTIm2JedeRL6YWlTgnH9PIuGq84OOnEbFjVN3Lbx3N1QuQfVA00CgYEAybA1uuBcXSCqfrIuVxkD2AIYHe1DvBdjhVpaKXKii78CTSmlzKg6svnhTrIQuZ4jyHZdeMzJrvzeaqZheaemdCP6XcA2lKRIbKMBrWAq00YGa1LhrwRJYlcKPJQiVVEPS+CY6FsJ+Edu4suBK7bS6ypOvhdv/FVQEPxT2PS8YNUCgYEAxwJ+8XNuw63ud9+Zi+gVjY4F8qWPwESLYz0DuOk2YlZAknpNVumTYBvUUSxBJYh8RFhtO+D53D5Z331oYKUzJ+EzII+qLAXvRBRBMz4O8YJHHkDXBugkphBDDV8B9QeLjeNSZnUWoDziOH6bqPwf8pgl9s/Ui6V1CHSVRpcBWwUCgYA2kMgu7qS5kLtUWySPzW4nTKwhN+HFTIbRrNrECxXmxroigTEyfBFuNR5QaeYYrAtqgY1m5Lev//2GnWM7dAr7hewj6qfGszrvegHsqMs4cakVqEOtbrWxL+WtWPaIdjJ+x7ZoMnZxZDg3ysemybNHHwSyBsp1TDc+glzmMtJtLA==" ], + "keyUse" : [ "SIG" ], + "certificate" : [ "MIICnTCCAYUCBgGVUbFIeTANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdzdHVkZW50MB4XDTI1MDMwMTEyMzAyN1oXDTM1MDMwMTEyMzIwN1owEjEQMA4GA1UEAwwHc3R1ZGVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANTEZgE/8iJpFXzzAcQtEB3QuA0H7llE4ynhJLvoDCPY1+QoVM881boHL2VpsQTXLzs+6ekfBHT5ZWSiMBUh+Vr0NcNVSIEMCJWH6Yv6ZJ337S3eujCNn160CtfXUU3kEYrxH9/Rk3wUNl3O8tau82zKOU1cQEydw4D4td3WDu81T6Rk4kEHmIns5XAXnchnuHEtYOqAaGlYn9UD2NTYtrxIyYXMzTBiONPLSBcLPBtOE5Z6PNeJ09MrHX5VEhnEVJLuNTbXzPYa+ey0OOfbBmIaPD59dZQ7olFpKJib9MtxidcBQb0Gw7yPukLxHRbtBsUoa5XDkazZo9wcDji4Qe8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAedqvKOBsz4IKKzkWHIQnN5H8dQKnuPUMdWewOwmMGIUdBU9k6aS+y+BB7mugF/Hnr8Lw5d2AHwVLj2VyP4Pq0d2My3Ihxi0vr6sSfxVHuD9y/a7FxDGVTkCvmy5DOmpF/kdNnL9xG5ZivHaucnrIHHGMcQCdbWAaac0qPZihv9pdMZFMtI3aiBO5jVJ7KP8iLNKsshg60mxCOPzauMVXi+rqqqhGAgMKAL4hjjvdIKTLWwmthnmAlGqlTk/7H82hS9aKygufXszXWdFAYhX/r8/hjyc+6zJUvkG20uRWnkR35gya7jQoZ2O6OvkQf0mgSvzgIP3xoYV2uKYD03wINg==" ], + "priority" : [ "100" ] + } + }, { + "id" : "3d6bfeeb-fa86-435e-8c39-6f547a0f4a38", + "name" : "hmac-generated-hs512", + "providerId" : "hmac-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "176e970f-5915-4d27-8233-8fab6d7ad947" ], + "secret" : [ "sXeOdtyIPpH_kcZWikHFjTur9yWok0QUwKi95l8wHp6kTVX9vhoZL2siNHRoFnn8tFgT4JZbR0bMsD57qAXlmVjA830Ny_GZdhL_PFWQh7JYMEJrl-1nyLy_SReQXRtq_q9tKUafUZqeYSKBlUYZ7D4jNRJ4-uniq80Ger-4ee0" ], + "priority" : [ "100" ], + "algorithm" : [ "HS512" ] + } + }, { + "id" : "df1247b5-041e-4ae8-b7fc-26c4b6f5ff67", + "name" : "rsa-enc-generated", + "providerId" : "rsa-enc-generated", + "subComponents" : { }, + "config" : { + "privateKey" : [ "MIIEpAIBAAKCAQEAq0piY/PaZh1IX46e0G6tCPtfRx7Q8zGslOFSBLR9PNAdSlBpYiV9kOpN1kTK2Sca5j4yyO9HAFK5j+zh/cy8SsP1iyuI0sCPG7NMKV1pP5Y753wTC0lTq8z16bvXPvPYrPRKgGDmU7Ww0/WD6/P+z9Li/+ujFHzzzfoPuQvbBhma6A4oadsC+zun/mWCyiD14mB+X00BeAIsxKJZ/Sd+U4lMkkvmpoXyx61xK+j48EAZ18u7FprlvUjgGzzAmm/K6O/fHPIw5eViVly7aj5gjh67ntSuZArVtrxy/Py5V4hkSO8guXKqNz3liJvLbFCqqpfTR/0duArZR0xcnaGc6wIDAQABAoIBAFRuu5YaXxbDq2eS5RzH2Vpakin7+jJOU4wljujL0QnXagC2J2QeJ8l1fT23tieZO4yvrxfVvnFd1aMouHMC5vORqWja4jxEd6ZHWKzxIw6ZbtjZk4eWMvy18KewlFavGyiR2GF0okQ0BMBOPqNhp8JoaMWOsNnKB+GJuBNWUTWtPWNQlbaeI+uIgFywrvZOcQuWqU+9Y5rQa7oKZisufu+z0vd9XyvjXQ/Thnuu9/k1m88EMAMS63zwfIOZm35PPqh1/6aBBcRWquT1X2S8g2hwmMLZJgU91yKtQcIujHXAcvxeK72/dcm8NU6AxM+8aj+821TvcNzJi7he5SGcin0CgYEA4cuxwqRixXz6yDcTv9GpJMULbJGjA+Qf/iSfT+ftBeKbnKgZGzHwOCTu5DMkag3BPjclut4sEt3QPf1cFv5vZvdkOnPeaFxrtoMhSz8ssh8qaOsObCwicel1zdPVTmMw7YzEZV14fdIq3lkHsLy2uWa0imRH0l4xTccmsJiPtU8CgYEAwjQtspxOejCyME+M+hcU3RelD6kaMjICuWGJj8g0OpqdHM7iNVJq78fOlWjntt/ydzfOXVMMVh4AG8dAvlc86iwwsBRsJPVrrrRoSNuAwFbjKisbjlnPbqyclHfUsyQitj19tp//ExH7JaBibzKd6KhqFuQTE1iYLs2mFQAz76UCgYEAsNLu64oGm7frQP345mAPgO8aqjRHIBX3g/Q0GsR61wAGcyElQCnUgHNT7burSa5p5goT7wpsI343xUPzaUJqBY25nRj+VGYEKFL6sM3Rd9B2SuHBUq8hbmmwyraYtiFxwKZbazJO2OHMloHMRvkSc5Dd0/8CS9ld7RYH04Y2DHsCgYEAoKXTK44baP7BWC9mOjc/vgjiNQs4rU8ra7igt7zwX44o63zEKUHNTh7l6DiIfYHRrAcRAahCazaT9makSxAVRs1ZVT7/mq8d7b41Chfx8KmvbuGMAPyQGEhXmoVqAOqigEhrptfBhD/6lkyPQNcJQz2VzOvMT9OYyBa8DWFGlTUCgYAfModz6g2HsYYr37/0ByXHKL0WQQtuAlZzCY9GuDLEok7QLFI/E+bdOHos3goW72Iswo/SO7inlW4S3gojuy+zZhwCO31T9p2Z0Yn0tDK3fkUO32flOLwxCZA99pKkIul3svl6643GqSD1feybmbYRtqoPCTSKSE9vI9T9DkBTvA==" ], + "keyUse" : [ "ENC" ], + "certificate" : [ "MIICnTCCAYUCBgGVUbFItzANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdzdHVkZW50MB4XDTI1MDMwMTEyMzAyN1oXDTM1MDMwMTEyMzIwN1owEjEQMA4GA1UEAwwHc3R1ZGVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtKYmPz2mYdSF+OntBurQj7X0ce0PMxrJThUgS0fTzQHUpQaWIlfZDqTdZEytknGuY+MsjvRwBSuY/s4f3MvErD9YsriNLAjxuzTCldaT+WO+d8EwtJU6vM9em71z7z2Kz0SoBg5lO1sNP1g+vz/s/S4v/roxR88836D7kL2wYZmugOKGnbAvs7p/5lgsog9eJgfl9NAXgCLMSiWf0nflOJTJJL5qaF8setcSvo+PBAGdfLuxaa5b1I4Bs8wJpvyujv3xzyMOXlYlZcu2o+YI4eu57UrmQK1ba8cvz8uVeIZEjvILlyqjc95Yiby2xQqqqX00f9HbgK2UdMXJ2hnOsCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAHfum0Ymw/qHTpjNeJjJyh5A1N4Z58m/PjuCXafIdDDjuAYpB3/M4bTGZRUvEvv2RuBNv3rONvMR8dRrZwio0/T0aEXnHrEAaCSfVcMy1To8TGGOzgtPMub4YCqXLMCwW5cwIbqT3P58HEqsqEbv7Zp4LtLYZBYXWDF8vM4zEn3CPYxuxRPKlrBUynRKYcwN7+/dbhJKiARpPMIZ5viGbjaTnNE/d/VFdv1q5xm3ItYnShDyJ0REGN18sWleLI6qkW0X22Gcjn38fWjiXDnF0HQYzC2UzMcEo/iLfPxTKbJnc+PPmnszfmCh7mWs5xVGfMOz/Oy8HI121x1ZSriRktA==" ], + "priority" : [ "100" ], + "algorithm" : [ "RSA-OAEP" ] + } + } ] + }, + "internationalizationEnabled" : false, + "supportedLocales" : [ ], + "authenticationFlows" : [ { + "id" : "f7d1108f-7994-47e5-81e9-1a88cdbe545c", + "alias" : "Account verification options", + "description" : "Method with which to verity the existing account", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-email-verification", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Verify Existing Account by Re-authentication", + "userSetupAllowed" : false + } ] + }, { + "id" : "cf40a5d3-bec8-4aef-9658-1b88c6cec561", + "alias" : "Browser - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "auth-otp-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "6820625f-5bb5-4fa2-8539-26a8568265c1", + "alias" : "Browser - Conditional Organization", + "description" : "Flow to determine if the organization identity-first login is to be used", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "organization", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "66d5e52e-592e-4cef-bfa0-512e90b609ec", + "alias" : "Direct Grant - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "direct-grant-validate-otp", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "b5bed405-b5f2-4839-861c-612501e4c412", + "alias" : "First Broker Login - Conditional Organization", + "description" : "Flow to determine if the authenticator that adds organization members is to be used", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "idp-add-organization-member", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "dd786e24-e822-43ec-be03-29874eb73737", + "alias" : "First broker login - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "auth-otp-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "8751572f-623e-4bdc-a02c-e92c15a91143", + "alias" : "Handle Existing Account", + "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-confirm-link", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Account verification options", + "userSetupAllowed" : false + } ] + }, { + "id" : "61efadf2-a54e-4071-b8c9-83e094525051", + "alias" : "Organization", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 10, + "autheticatorFlow" : true, + "flowAlias" : "Browser - Conditional Organization", + "userSetupAllowed" : false + } ] + }, { + "id" : "b99c3a7a-8ef7-46b1-b8a1-cb51f8a6e725", + "alias" : "Reset - Conditional OTP", + "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "reset-otp", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "a3bfc2e4-af67-4d3e-851f-3c58bf32be83", + "alias" : "User creation or linking", + "description" : "Flow for the existing/non-existing user alternatives", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticatorConfig" : "create unique user config", + "authenticator" : "idp-create-user-if-unique", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Handle Existing Account", + "userSetupAllowed" : false + } ] + }, { + "id" : "4cc3bf25-d1b7-43a6-8619-5ed5f2d65aed", + "alias" : "Verify Existing Account by Re-authentication", + "description" : "Reauthentication of existing account", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-username-password-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "First broker login - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "4e5564ce-87da-4b25-8dcb-062216ceaa8d", + "alias" : "browser", + "description" : "Browser based authentication", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "auth-cookie", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "auth-spnego", + "authenticatorFlow" : false, + "requirement" : "DISABLED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "identity-provider-redirector", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 25, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 26, + "autheticatorFlow" : true, + "flowAlias" : "Organization", + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 30, + "autheticatorFlow" : true, + "flowAlias" : "forms", + "userSetupAllowed" : false + } ] + }, { + "id" : "def90462-5831-4856-b186-05df9e640bbb", + "alias" : "clients", + "description" : "Base authentication for clients", + "providerId" : "client-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "client-secret", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "client-jwt", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "client-secret-jwt", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 30, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "client-x509", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 40, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "f8c9010d-f197-417b-bda1-2993e1a73a21", + "alias" : "direct grant", + "description" : "OpenID Connect Resource Owner Grant", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "direct-grant-validate-username", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "direct-grant-validate-password", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 30, + "autheticatorFlow" : true, + "flowAlias" : "Direct Grant - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "0fb9e2a4-ea0d-453f-a1fe-f000c849fd66", + "alias" : "docker auth", + "description" : "Used by Docker clients to authenticate against the IDP", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "docker-http-basic-authenticator", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "79a9efc4-1279-4093-8914-92f4e0b02bb4", + "alias" : "first broker login", + "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticatorConfig" : "review profile config", + "authenticator" : "idp-review-profile", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "User creation or linking", + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 50, + "autheticatorFlow" : true, + "flowAlias" : "First Broker Login - Conditional Organization", + "userSetupAllowed" : false + } ] + }, { + "id" : "f855b3a1-6612-4528-94bc-d0793bfda561", + "alias" : "forms", + "description" : "Username, password, otp and other auth forms.", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "auth-username-password-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Browser - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "fb84970b-6f04-4849-a385-792e17c1b8ce", + "alias" : "registration", + "description" : "Registration flow", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "registration-page-form", + "authenticatorFlow" : true, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : true, + "flowAlias" : "registration form", + "userSetupAllowed" : false + } ] + }, { + "id" : "fcdfd4d4-1c04-487d-aa7c-85e136814274", + "alias" : "registration form", + "description" : "Registration form", + "providerId" : "form-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "registration-user-creation", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "registration-password-action", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 50, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "registration-recaptcha-action", + "authenticatorFlow" : false, + "requirement" : "DISABLED", + "priority" : 60, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "registration-terms-and-conditions", + "authenticatorFlow" : false, + "requirement" : "DISABLED", + "priority" : 70, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "306d8f7d-c12a-46cb-9a68-c6c3f1622f57", + "alias" : "reset credentials", + "description" : "Reset credentials for a user if they forgot their password or something", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "reset-credentials-choose-user", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "reset-credential-email", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "reset-password", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 30, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 40, + "autheticatorFlow" : true, + "flowAlias" : "Reset - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "35a54b09-ff8c-46c4-9f04-1efbb153276c", + "alias" : "saml ecp", + "description" : "SAML ECP Profile Authentication Flow", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "http-basic-authenticator", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + } ], + "authenticatorConfig" : [ { + "id" : "fc1b82d7-593d-4906-a4d9-13220b66b7ce", + "alias" : "create unique user config", + "config" : { + "require.password.update.after.registration" : "false" + } + }, { + "id" : "a90543f4-7da7-43bc-8737-7e58dd190014", + "alias" : "review profile config", + "config" : { + "update.profile.on.first.login" : "missing" + } + } ], + "requiredActions" : [ { + "alias" : "CONFIGURE_TOTP", + "name" : "Configure OTP", + "providerId" : "CONFIGURE_TOTP", + "enabled" : true, + "defaultAction" : false, + "priority" : 10, + "config" : { } + }, { + "alias" : "TERMS_AND_CONDITIONS", + "name" : "Terms and Conditions", + "providerId" : "TERMS_AND_CONDITIONS", + "enabled" : false, + "defaultAction" : false, + "priority" : 20, + "config" : { } + }, { + "alias" : "UPDATE_PASSWORD", + "name" : "Update Password", + "providerId" : "UPDATE_PASSWORD", + "enabled" : true, + "defaultAction" : false, + "priority" : 30, + "config" : { } + }, { + "alias" : "UPDATE_PROFILE", + "name" : "Update Profile", + "providerId" : "UPDATE_PROFILE", + "enabled" : true, + "defaultAction" : false, + "priority" : 40, + "config" : { } + }, { + "alias" : "VERIFY_EMAIL", + "name" : "Verify Email", + "providerId" : "VERIFY_EMAIL", + "enabled" : true, + "defaultAction" : false, + "priority" : 50, + "config" : { } + }, { + "alias" : "delete_account", + "name" : "Delete Account", + "providerId" : "delete_account", + "enabled" : false, + "defaultAction" : false, + "priority" : 60, + "config" : { } + }, { + "alias" : "webauthn-register", + "name" : "Webauthn Register", + "providerId" : "webauthn-register", + "enabled" : true, + "defaultAction" : false, + "priority" : 70, + "config" : { } + }, { + "alias" : "webauthn-register-passwordless", + "name" : "Webauthn Register Passwordless", + "providerId" : "webauthn-register-passwordless", + "enabled" : true, + "defaultAction" : false, + "priority" : 80, + "config" : { } + }, { + "alias" : "VERIFY_PROFILE", + "name" : "Verify Profile", + "providerId" : "VERIFY_PROFILE", + "enabled" : true, + "defaultAction" : false, + "priority" : 90, + "config" : { } + }, { + "alias" : "delete_credential", + "name" : "Delete Credential", + "providerId" : "delete_credential", + "enabled" : true, + "defaultAction" : false, + "priority" : 100, + "config" : { } + }, { + "alias" : "update_user_locale", + "name" : "Update User Locale", + "providerId" : "update_user_locale", + "enabled" : true, + "defaultAction" : false, + "priority" : 1000, + "config" : { } + } ], + "browserFlow" : "browser", + "registrationFlow" : "registration", + "directGrantFlow" : "direct grant", + "resetCredentialsFlow" : "reset credentials", + "clientAuthenticationFlow" : "clients", + "dockerAuthenticationFlow" : "docker auth", + "firstBrokerLoginFlow" : "first broker login", + "attributes" : { + "cibaBackchannelTokenDeliveryMode" : "poll", + "cibaExpiresIn" : "120", + "cibaAuthRequestedUserHint" : "login_hint", + "oauth2DeviceCodeLifespan" : "600", + "oauth2DevicePollingInterval" : "5", + "parRequestUriLifespan" : "60", + "cibaInterval" : "5", + "realmReusableOtpCode" : "false" + }, + "keycloakVersion" : "26.1.3", + "userManagedAccessAllowed" : false, + "organizationsEnabled" : false, + "verifiableCredentialsEnabled" : false, + "adminPermissionsEnabled" : false, + "clientProfiles" : { + "profiles" : [ ] + }, + "clientPolicies" : { + "policies" : [ ] + } +} diff --git a/idp/teacher-realm.json b/idp/teacher-realm.json new file mode 100644 index 00000000..5584f692 --- /dev/null +++ b/idp/teacher-realm.json @@ -0,0 +1,2060 @@ +{ + "id" : "02ba6887-22f5-4de4-ad9b-cb2a2060bce1", + "realm" : "teacher", + "notBefore" : 0, + "defaultSignatureAlgorithm" : "RS256", + "revokeRefreshToken" : false, + "refreshTokenMaxReuse" : 0, + "accessTokenLifespan" : 300, + "accessTokenLifespanForImplicitFlow" : 900, + "ssoSessionIdleTimeout" : 1800, + "ssoSessionMaxLifespan" : 36000, + "ssoSessionIdleTimeoutRememberMe" : 0, + "ssoSessionMaxLifespanRememberMe" : 0, + "offlineSessionIdleTimeout" : 2592000, + "offlineSessionMaxLifespanEnabled" : false, + "offlineSessionMaxLifespan" : 5184000, + "clientSessionIdleTimeout" : 0, + "clientSessionMaxLifespan" : 0, + "clientOfflineSessionIdleTimeout" : 0, + "clientOfflineSessionMaxLifespan" : 0, + "accessCodeLifespan" : 60, + "accessCodeLifespanUserAction" : 300, + "accessCodeLifespanLogin" : 1800, + "actionTokenGeneratedByAdminLifespan" : 43200, + "actionTokenGeneratedByUserLifespan" : 300, + "oauth2DeviceCodeLifespan" : 600, + "oauth2DevicePollingInterval" : 5, + "enabled" : true, + "sslRequired" : "external", + "registrationAllowed" : false, + "registrationEmailAsUsername" : false, + "rememberMe" : false, + "verifyEmail" : false, + "loginWithEmailAllowed" : true, + "duplicateEmailsAllowed" : false, + "resetPasswordAllowed" : false, + "editUsernameAllowed" : false, + "bruteForceProtected" : false, + "permanentLockout" : false, + "maxTemporaryLockouts" : 0, + "bruteForceStrategy" : "MULTIPLE", + "maxFailureWaitSeconds" : 900, + "minimumQuickLoginWaitSeconds" : 60, + "waitIncrementSeconds" : 60, + "quickLoginCheckMilliSeconds" : 1000, + "maxDeltaTimeSeconds" : 43200, + "failureFactor" : 30, + "roles" : { + "realm" : [ { + "id" : "e7f1e366-0bfc-4469-bcde-92bcd1ed5ce7", + "name" : "uma_authorization", + "description" : "${role_uma_authorization}", + "composite" : false, + "clientRole" : false, + "containerId" : "02ba6887-22f5-4de4-ad9b-cb2a2060bce1", + "attributes" : { } + }, { + "id" : "6b546a34-4ebe-4c09-b274-fc1f6bebdf93", + "name" : "default-roles-teacher", + "description" : "${role_default-roles}", + "composite" : true, + "composites" : { + "realm" : [ "offline_access", "uma_authorization" ], + "client" : { + "account" : [ "manage-account", "view-profile" ] + } + }, + "clientRole" : false, + "containerId" : "02ba6887-22f5-4de4-ad9b-cb2a2060bce1", + "attributes" : { } + }, { + "id" : "747c4433-f128-4f72-b56f-315e7779d4fd", + "name" : "offline_access", + "description" : "${role_offline-access}", + "composite" : false, + "clientRole" : false, + "containerId" : "02ba6887-22f5-4de4-ad9b-cb2a2060bce1", + "attributes" : { } + } ], + "client" : { + "realm-management" : [ { + "id" : "4c8243b1-b576-4cb2-a4f7-3ce25e408fe5", + "name" : "impersonation", + "description" : "${role_impersonation}", + "composite" : false, + "clientRole" : true, + "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes" : { } + }, { + "id" : "71fd672b-024b-4d44-b058-03320aeb1842", + "name" : "view-users", + "description" : "${role_view-users}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-groups", "query-users" ] + } + }, + "clientRole" : true, + "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes" : { } + }, { + "id" : "fea88d42-3065-4600-a5b6-c4e2589e1304", + "name" : "view-events", + "description" : "${role_view-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes" : { } + }, { + "id" : "6247b5b0-4d41-4fda-900c-3dfc725e03a2", + "name" : "manage-users", + "description" : "${role_manage-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes" : { } + }, { + "id" : "a3b55a4b-b7f9-4db3-a64f-6ddf80bf74e7", + "name" : "view-authorization", + "description" : "${role_view-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes" : { } + }, { + "id" : "d6714bc8-ff2d-4da0-98b4-2a6479e67954", + "name" : "manage-events", + "description" : "${role_manage-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes" : { } + }, { + "id" : "d389da82-1730-4c66-9b43-34ac3c8d7f6c", + "name" : "query-realms", + "description" : "${role_query-realms}", + "composite" : false, + "clientRole" : true, + "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes" : { } + }, { + "id" : "4dc3905f-311b-4de0-b2e6-a3de50a078a3", + "name" : "query-users", + "description" : "${role_query-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes" : { } + }, { + "id" : "28ea5d84-4e7d-484e-82fa-c9adcea4ffc0", + "name" : "manage-identity-providers", + "description" : "${role_manage-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes" : { } + }, { + "id" : "e020bc9c-f2c9-4023-82eb-b62266749334", + "name" : "query-clients", + "description" : "${role_query-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes" : { } + }, { + "id" : "e7373af5-924a-4f01-b34d-55a09aac6c74", + "name" : "manage-clients", + "description" : "${role_manage-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes" : { } + }, { + "id" : "0879b6d5-7db6-4c83-8b99-e889028cb13e", + "name" : "manage-realm", + "description" : "${role_manage-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes" : { } + }, { + "id" : "ff2c82f3-7f04-4ced-9127-65097e2c16b9", + "name" : "realm-admin", + "description" : "${role_realm-admin}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "impersonation", "view-users", "view-events", "manage-users", "view-authorization", "query-users", "query-realms", "manage-events", "manage-identity-providers", "query-clients", "manage-realm", "view-clients", "manage-clients", "query-groups", "create-client", "view-realm", "manage-authorization", "view-identity-providers" ] + } + }, + "clientRole" : true, + "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes" : { } + }, { + "id" : "156a28de-00d8-4828-9dc9-e09e7841312f", + "name" : "view-clients", + "description" : "${role_view-clients}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-clients" ] + } + }, + "clientRole" : true, + "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes" : { } + }, { + "id" : "a241d7dd-b028-474a-bdf8-4d33e00c1b90", + "name" : "create-client", + "description" : "${role_create-client}", + "composite" : false, + "clientRole" : true, + "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes" : { } + }, { + "id" : "681e3f7e-bb8c-4e09-a49e-ba8c21f916ff", + "name" : "query-groups", + "description" : "${role_query-groups}", + "composite" : false, + "clientRole" : true, + "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes" : { } + }, { + "id" : "1c5886ad-b354-4246-b288-13ea7635db58", + "name" : "view-realm", + "description" : "${role_view-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes" : { } + }, { + "id" : "7dedf6ff-b715-4f14-85ac-40d0652f153d", + "name" : "manage-authorization", + "description" : "${role_manage-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes" : { } + }, { + "id" : "694721e8-3bf3-47b5-ae38-874db0dc7740", + "name" : "view-identity-providers", + "description" : "${role_view-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes" : { } + } ], + "dwengo" : [ ], + "security-admin-console" : [ ], + "admin-cli" : [ ], + "account-console" : [ ], + "broker" : [ { + "id" : "0cb1b2b5-a751-4f09-ac2f-ea26c398a857", + "name" : "read-token", + "description" : "${role_read-token}", + "composite" : false, + "clientRole" : true, + "containerId" : "cfd0202e-a6b9-4c5e-9f49-2ef17df9089b", + "attributes" : { } + } ], + "account" : [ { + "id" : "d21c51c5-353c-4d78-8c8d-8b8e9f37efa8", + "name" : "manage-account-links", + "description" : "${role_manage-account-links}", + "composite" : false, + "clientRole" : true, + "containerId" : "7ceb65eb-30da-4dc3-95bc-f06863362fd6", + "attributes" : { } + }, { + "id" : "49c8ac02-defa-41af-9e63-2fd24cfc103f", + "name" : "view-groups", + "description" : "${role_view-groups}", + "composite" : false, + "clientRole" : true, + "containerId" : "7ceb65eb-30da-4dc3-95bc-f06863362fd6", + "attributes" : { } + }, { + "id" : "3850c5cc-510a-417b-9976-a1d1d6650804", + "name" : "manage-account", + "description" : "${role_manage-account}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "manage-account-links" ] + } + }, + "clientRole" : true, + "containerId" : "7ceb65eb-30da-4dc3-95bc-f06863362fd6", + "attributes" : { } + }, { + "id" : "6554709e-304a-428f-8665-970aacd1dae8", + "name" : "view-consent", + "description" : "${role_view-consent}", + "composite" : false, + "clientRole" : true, + "containerId" : "7ceb65eb-30da-4dc3-95bc-f06863362fd6", + "attributes" : { } + }, { + "id" : "7a0c9d85-daea-4b80-93b5-095e21e5d569", + "name" : "delete-account", + "description" : "${role_delete-account}", + "composite" : false, + "clientRole" : true, + "containerId" : "7ceb65eb-30da-4dc3-95bc-f06863362fd6", + "attributes" : { } + }, { + "id" : "ee2c5cff-1b05-417f-ab3a-a796be754299", + "name" : "manage-consent", + "description" : "${role_manage-consent}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "view-consent" ] + } + }, + "clientRole" : true, + "containerId" : "7ceb65eb-30da-4dc3-95bc-f06863362fd6", + "attributes" : { } + }, { + "id" : "128fb31d-0784-4b4e-9aa5-82ceb2824fa0", + "name" : "view-profile", + "description" : "${role_view-profile}", + "composite" : false, + "clientRole" : true, + "containerId" : "7ceb65eb-30da-4dc3-95bc-f06863362fd6", + "attributes" : { } + }, { + "id" : "ca850b8d-b75b-4b04-9e42-1e4cc8ab2179", + "name" : "view-applications", + "description" : "${role_view-applications}", + "composite" : false, + "clientRole" : true, + "containerId" : "7ceb65eb-30da-4dc3-95bc-f06863362fd6", + "attributes" : { } + } ] + } + }, + "groups" : [ ], + "defaultRole" : { + "id" : "6b546a34-4ebe-4c09-b274-fc1f6bebdf93", + "name" : "default-roles-teacher", + "description" : "${role_default-roles}", + "composite" : true, + "clientRole" : false, + "containerId" : "02ba6887-22f5-4de4-ad9b-cb2a2060bce1" + }, + "requiredCredentials" : [ "password" ], + "otpPolicyType" : "totp", + "otpPolicyAlgorithm" : "HmacSHA1", + "otpPolicyInitialCounter" : 0, + "otpPolicyDigits" : 6, + "otpPolicyLookAheadWindow" : 1, + "otpPolicyPeriod" : 30, + "otpPolicyCodeReusable" : false, + "otpSupportedApplications" : [ "totpAppFreeOTPName", "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName" ], + "localizationTexts" : { }, + "webAuthnPolicyRpEntityName" : "keycloak", + "webAuthnPolicySignatureAlgorithms" : [ "ES256", "RS256" ], + "webAuthnPolicyRpId" : "", + "webAuthnPolicyAttestationConveyancePreference" : "not specified", + "webAuthnPolicyAuthenticatorAttachment" : "not specified", + "webAuthnPolicyRequireResidentKey" : "not specified", + "webAuthnPolicyUserVerificationRequirement" : "not specified", + "webAuthnPolicyCreateTimeout" : 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister" : false, + "webAuthnPolicyAcceptableAaguids" : [ ], + "webAuthnPolicyExtraOrigins" : [ ], + "webAuthnPolicyPasswordlessRpEntityName" : "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms" : [ "ES256", "RS256" ], + "webAuthnPolicyPasswordlessRpId" : "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference" : "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment" : "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey" : "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement" : "not specified", + "webAuthnPolicyPasswordlessCreateTimeout" : 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false, + "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ], + "webAuthnPolicyPasswordlessExtraOrigins" : [ ], + "users" : [ { + "id" : "63dbbb64-c09f-4e4e-9cbf-af9e557dbb09", + "username" : "testleerkracht1", + "firstName" : "Kris", + "lastName" : "Coolsaet", + "email" : "kris.coolsaet@ugent.be", + "emailVerified" : false, + "createdTimestamp" : 1740866530658, + "enabled" : true, + "totp" : false, + "credentials" : [ { + "id" : "c5382bf7-ccc6-47de-93b9-2c11ea7b6862", + "type" : "password", + "userLabel" : "My password", + "createdDate" : 1740866544032, + "secretData" : "{\"value\":\"H2vKyHF3j/alz6CNap2uaKSRb+/wrWImVecj7dcHe1w=\",\"salt\":\"32WjW1KzFaR5RJqU0Pfq9w==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-teacher" ], + "notBefore" : 0, + "groups" : [ ] + } ], + "scopeMappings" : [ { + "clientScope" : "offline_access", + "roles" : [ "offline_access" ] + } ], + "clientScopeMappings" : { + "account" : [ { + "client" : "account-console", + "roles" : [ "manage-account", "view-groups" ] + } ] + }, + "clients" : [ { + "id" : "7ceb65eb-30da-4dc3-95bc-f06863362fd6", + "clientId" : "account", + "name" : "${client_account}", + "rootUrl" : "${authBaseUrl}", + "baseUrl" : "/realms/teacher/account/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/realms/teacher/account/*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "realm_client" : "false", + "post.logout.redirect.uris" : "+" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "roles", "profile", "basic", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] + }, { + "id" : "920e8621-36b5-4046-b1cd-4b293668f64b", + "clientId" : "account-console", + "name" : "${client_account-console}", + "rootUrl" : "${authBaseUrl}", + "baseUrl" : "/realms/teacher/account/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/realms/teacher/account/*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "realm_client" : "false", + "post.logout.redirect.uris" : "+", + "pkce.code.challenge.method" : "S256" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "protocolMappers" : [ { + "id" : "cd3f4ae0-3008-488b-88c5-b6d640a9edd3", + "name" : "audience resolve", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-audience-resolve-mapper", + "consentRequired" : false, + "config" : { } + } ], + "defaultClientScopes" : [ "web-origins", "acr", "roles", "profile", "basic", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] + }, { + "id" : "9d7b2827-b7bb-451e-ad38-8f55a69f7c9c", + "clientId" : "admin-cli", + "name" : "${client_admin-cli}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : false, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "realm_client" : "false", + "client.use.lightweight.access.token.enabled" : "true" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : true, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "roles", "profile", "basic", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] + }, { + "id" : "cfd0202e-a6b9-4c5e-9f49-2ef17df9089b", + "clientId" : "broker", + "name" : "${client_broker}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : true, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "realm_client" : "true" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "roles", "profile", "basic", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] + }, { + "id" : "abdee18a-4549-48b5-b976-4c1a42820ef9", + "clientId" : "dwengo", + "name" : "Dwengo", + "description" : "", + "rootUrl" : "http://localhost:3000", + "adminUrl" : "http://localhost:3000", + "baseUrl" : "http://localhost:3000", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "urn:ietf:wg:oauth:2.0:oob", "http://localhost:3000/*", "http://localhost:3000" ], + "webOrigins" : [ "+" ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : true, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : true, + "protocol" : "openid-connect", + "attributes" : { + "realm_client" : "false", + "oidc.ciba.grant.enabled" : "false", + "backchannel.logout.session.required" : "true", + "post.logout.redirect.uris" : "+", + "frontchannel.logout.session.required" : "true", + "oauth2.device.authorization.grant.enabled" : "false", + "display.on.consent.screen" : "false", + "backchannel.logout.revoke.offline.tokens" : "false" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : true, + "nodeReRegistrationTimeout" : -1, + "defaultClientScopes" : [ "web-origins", "acr", "roles", "profile", "basic", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] + }, { + "id" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "clientId" : "realm-management", + "name" : "${client_realm-management}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : true, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "realm_client" : "true" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "roles", "profile", "basic", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] + }, { + "id" : "c421853c-5bdf-4ea9-ae97-51f5ad7b8df8", + "clientId" : "security-admin-console", + "name" : "${client_security-admin-console}", + "rootUrl" : "${authAdminUrl}", + "baseUrl" : "/admin/teacher/console/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/admin/teacher/console/*" ], + "webOrigins" : [ "+" ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "realm_client" : "false", + "client.use.lightweight.access.token.enabled" : "true", + "post.logout.redirect.uris" : "+", + "pkce.code.challenge.method" : "S256" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : true, + "nodeReRegistrationTimeout" : 0, + "protocolMappers" : [ { + "id" : "a9a893af-925e-46c9-ba33-47b06101ce5f", + "name" : "locale", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "locale", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "locale", + "jsonType.label" : "String" + } + } ], + "defaultClientScopes" : [ "web-origins", "acr", "roles", "profile", "basic", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] + } ], + "clientScopes" : [ { + "id" : "fef4fbeb-d7e6-4474-b802-6c63df0dc9a3", + "name" : "saml_organization", + "description" : "Organization Membership", + "protocol" : "saml", + "attributes" : { + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "2384b79b-5cc3-4e1c-b4b2-4bee2ceeed72", + "name" : "organization", + "protocol" : "saml", + "protocolMapper" : "saml-organization-membership-mapper", + "consentRequired" : false, + "config" : { } + } ] + }, { + "id" : "a097893c-7eed-4556-b2ed-3751c7fc3c51", + "name" : "offline_access", + "description" : "OpenID Connect built-in scope: offline_access", + "protocol" : "openid-connect", + "attributes" : { + "consent.screen.text" : "${offlineAccessScopeConsentText}", + "display.on.consent.screen" : "true" + } + }, { + "id" : "ffc38cb2-eb10-47cf-a2d6-6647fdd4da65", + "name" : "service_account", + "description" : "Specific scope for a client enabled for service accounts", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "06ed3629-1c3d-48d9-80c6-98fcd3958c48", + "name" : "Client Host", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientHost", + "id.token.claim" : "true", + "introspection.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientHost", + "jsonType.label" : "String" + } + }, { + "id" : "04eeb81e-05c0-484a-91df-9a79138bcd66", + "name" : "Client IP Address", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientAddress", + "id.token.claim" : "true", + "introspection.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientAddress", + "jsonType.label" : "String" + } + }, { + "id" : "6e673f49-ce38-4583-8040-8a2e7ec5e7c8", + "name" : "Client ID", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "client_id", + "id.token.claim" : "true", + "introspection.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "client_id", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "ee188d9c-ab26-4e53-a16c-c9f77094f854", + "name" : "profile", + "description" : "OpenID Connect built-in scope: profile", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "consent.screen.text" : "${profileScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "05ff270b-6a50-4bbb-903d-9546a59f20bf", + "name" : "picture", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "picture", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "picture", + "jsonType.label" : "String" + } + }, { + "id" : "394f808d-bc7b-476e-a372-7cfece5c6db0", + "name" : "gender", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "gender", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "gender", + "jsonType.label" : "String" + } + }, { + "id" : "0371c44f-c6e0-4f88-ac8f-17a56e2b90f8", + "name" : "profile", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "profile", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "profile", + "jsonType.label" : "String" + } + }, { + "id" : "21d66073-42f2-443b-aac4-e49c9038253c", + "name" : "birthdate", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "birthdate", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "birthdate", + "jsonType.label" : "String" + } + }, { + "id" : "5cc6a97f-9d1a-4c72-b682-af6d1bd36883", + "name" : "full name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-full-name-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "introspection.token.claim" : "true", + "access.token.claim" : "true", + "userinfo.token.claim" : "true" + } + }, { + "id" : "d6a6d46b-80a7-4228-af07-0faae2911fed", + "name" : "nickname", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "nickname", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "nickname", + "jsonType.label" : "String" + } + }, { + "id" : "322b508a-7464-4b0f-90df-3f489975a62e", + "name" : "zoneinfo", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "zoneinfo", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "zoneinfo", + "jsonType.label" : "String" + } + }, { + "id" : "f757ae7a-3005-4899-bb4e-da1ab4b47bb0", + "name" : "locale", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "locale", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "locale", + "jsonType.label" : "String" + } + }, { + "id" : "bab8eb17-0cb0-4275-8456-aa1d65933a35", + "name" : "updated at", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "updatedAt", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "updated_at", + "jsonType.label" : "long" + } + }, { + "id" : "6ea1d43c-d4c7-4f2f-93b0-dfdb3bb584eb", + "name" : "given name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "firstName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "given_name", + "jsonType.label" : "String" + } + }, { + "id" : "3a2ebc93-05fb-4904-996b-5e3331b72fcd", + "name" : "family name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "lastName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "family_name", + "jsonType.label" : "String" + } + }, { + "id" : "217b417e-d4f6-4225-bf92-3bd38f6fbefb", + "name" : "username", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "username", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "preferred_username", + "jsonType.label" : "String" + } + }, { + "id" : "3dd5da51-5842-4358-a69f-f7ffffe521ac", + "name" : "website", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "website", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "website", + "jsonType.label" : "String" + } + }, { + "id" : "790bda99-1c27-4970-b3b9-4fa1c90c738c", + "name" : "middle name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "middleName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "middle_name", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "e6cf59c7-9390-4f48-ab01-79a0fa138960", + "name" : "organization", + "description" : "Additional claims about the organization a subject belongs to", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "consent.screen.text" : "${organizationScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "417ff129-6b95-4e95-9f57-a6699ca18d8d", + "name" : "organization", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-organization-membership-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "introspection.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "organization", + "jsonType.label" : "String", + "multivalued" : "true" + } + } ] + }, { + "id" : "43d92ef5-76d8-4df0-84b5-5f833875d345", + "name" : "email", + "description" : "OpenID Connect built-in scope: email", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "consent.screen.text" : "${emailScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "74d21718-190a-4c53-b446-b07e5f029394", + "name" : "email verified", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "emailVerified", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "email_verified", + "jsonType.label" : "boolean" + } + }, { + "id" : "949871a0-d68c-4563-a9b3-945a3148f937", + "name" : "email", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "email", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "email", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "b07a2014-d07e-450f-a593-66e9f9cf4799", + "name" : "acr", + "description" : "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "79efdc37-0f06-43e6-a516-7bc9dc29f04d", + "name" : "acr loa level", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-acr-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "introspection.token.claim" : "true", + "access.token.claim" : "true" + } + } ] + }, { + "id" : "3bbbff21-0446-4813-8bdf-54c35d8fffca", + "name" : "microprofile-jwt", + "description" : "Microprofile - JWT built-in scope", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "0e996cda-fe5b-439d-ba4c-cf2129ae812f", + "name" : "upn", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "username", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "upn", + "jsonType.label" : "String" + } + }, { + "id" : "ddf1efe2-e765-475c-a4a0-d52f1f597834", + "name" : "groups", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-realm-role-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "multivalued" : "true", + "user.attribute" : "foo", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "groups", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "93a40d0e-f163-42f7-a9d4-53cc2e17914e", + "name" : "basic", + "description" : "OpenID Connect scope for add all basic claims to the token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "41eb9e93-8e04-404b-a12b-40ef5a55f640", + "name" : "sub", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-sub-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "access.token.claim" : "true" + } + }, { + "id" : "1291062a-10f6-4061-b9ea-f54ff5d8ec54", + "name" : "auth_time", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "AUTH_TIME", + "id.token.claim" : "true", + "introspection.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "auth_time", + "jsonType.label" : "long" + } + } ] + }, { + "id" : "9ea27173-e54b-42f0-8f6c-5a36c5073ede", + "name" : "role_list", + "description" : "SAML role list", + "protocol" : "saml", + "attributes" : { + "consent.screen.text" : "${samlRoleListScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "d10a6975-8aeb-4215-8d6b-23b0286d4abb", + "name" : "role list", + "protocol" : "saml", + "protocolMapper" : "saml-role-list-mapper", + "consentRequired" : false, + "config" : { + "single" : "false", + "attribute.nameformat" : "Basic", + "attribute.name" : "Role" + } + } ] + }, { + "id" : "e8a99a5a-1519-4c7d-a3f0-ac6d34c61a0b", + "name" : "phone", + "description" : "OpenID Connect built-in scope: phone", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "consent.screen.text" : "${phoneScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "b2de087f-169f-44b3-ad46-3a063ac9025f", + "name" : "phone number", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "phoneNumber", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "phone_number", + "jsonType.label" : "String" + } + }, { + "id" : "ffb8aebd-0d03-4811-8fd4-aa03bda36b2d", + "name" : "phone number verified", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "phoneNumberVerified", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "phone_number_verified", + "jsonType.label" : "boolean" + } + } ] + }, { + "id" : "30e06d84-f610-4f17-8820-6f785a510357", + "name" : "address", + "description" : "OpenID Connect built-in scope: address", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "consent.screen.text" : "${addressScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "de707a09-a895-4b67-9ac5-0ff4e69715ea", + "name" : "address", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-address-mapper", + "consentRequired" : false, + "config" : { + "user.attribute.formatted" : "formatted", + "user.attribute.country" : "country", + "introspection.token.claim" : "true", + "user.attribute.postal_code" : "postal_code", + "userinfo.token.claim" : "true", + "user.attribute.street" : "street", + "id.token.claim" : "true", + "user.attribute.region" : "region", + "access.token.claim" : "true", + "user.attribute.locality" : "locality" + } + } ] + }, { + "id" : "1762c903-9f07-451c-915d-855488e4aa42", + "name" : "web-origins", + "description" : "OpenID Connect scope for add allowed web origins to the access token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "consent.screen.text" : "", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "0164bdc3-c79d-4467-b6bf-ca9a6889d04c", + "name" : "allowed web origins", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-allowed-origins-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "access.token.claim" : "true" + } + } ] + }, { + "id" : "91301d6d-0bb9-4da6-b8db-ee2480e25fee", + "name" : "roles", + "description" : "OpenID Connect scope for add user roles to the access token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "consent.screen.text" : "${rolesScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "2880d772-b0da-4ee8-bf1e-3f729a945db9", + "name" : "realm roles", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-realm-role-mapper", + "consentRequired" : false, + "config" : { + "user.attribute" : "foo", + "introspection.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "realm_access.roles", + "jsonType.label" : "String", + "multivalued" : "true" + } + }, { + "id" : "535042c5-58c5-4225-94b8-0b5b3411968e", + "name" : "client roles", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-client-role-mapper", + "consentRequired" : false, + "config" : { + "user.attribute" : "foo", + "introspection.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "resource_access.${client_id}.roles", + "jsonType.label" : "String", + "multivalued" : "true" + } + }, { + "id" : "a88432f1-565f-480d-958d-a5cea1dbcf0a", + "name" : "audience resolve", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-audience-resolve-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "access.token.claim" : "true" + } + } ] + } ], + "defaultDefaultClientScopes" : [ "role_list", "saml_organization", "profile", "email", "roles", "web-origins", "acr", "basic" ], + "defaultOptionalClientScopes" : [ "offline_access", "address", "phone", "microprofile-jwt", "organization" ], + "browserSecurityHeaders" : { + "contentSecurityPolicyReportOnly" : "", + "xContentTypeOptions" : "nosniff", + "referrerPolicy" : "no-referrer", + "xRobotsTag" : "none", + "xFrameOptions" : "SAMEORIGIN", + "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection" : "1; mode=block", + "strictTransportSecurity" : "max-age=31536000; includeSubDomains" + }, + "smtpServer" : { }, + "eventsEnabled" : false, + "eventsListeners" : [ "jboss-logging" ], + "enabledEventTypes" : [ ], + "adminEventsEnabled" : false, + "adminEventsDetailsEnabled" : false, + "identityProviders" : [ ], + "identityProviderMappers" : [ ], + "components" : { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ { + "id" : "a689e06a-e440-4d94-ba54-692fba5a5486", + "name" : "Max Clients Limit", + "providerId" : "max-clients", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "max-clients" : [ "200" ] + } + }, { + "id" : "2778fda5-0a9f-40ab-ab4b-054ff8ce38e9", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ] + } + }, { + "id" : "36dc0167-9c9a-4b4a-9f04-29129aecac4d", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "saml-user-property-mapper", "oidc-address-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper" ] + } + }, { + "id" : "4b79c6fd-5166-4bc2-ab0b-bff0018452f6", + "name" : "Consent Required", + "providerId" : "consent-required", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "2003600a-89fb-421e-9dfe-d5096ee7fd4e", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-role-list-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper" ] + } + }, { + "id" : "d62a2e93-f877-462a-bad3-93dcf91d49d2", + "name" : "Trusted Hosts", + "providerId" : "trusted-hosts", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "host-sending-registration-request-must-match" : [ "true" ], + "client-uris-must-match" : [ "true" ] + } + }, { + "id" : "6e659a80-a638-4504-b507-21b9f77586ed", + "name" : "Full Scope Disabled", + "providerId" : "scope", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "9ef67c59-5c3e-40cf-90ee-516b2e35ed3d", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ] + } + } ], + "org.keycloak.keys.KeyProvider" : [ { + "id" : "b5365a56-e00d-4612-80bf-262a9c8dba7c", + "name" : "rsa-enc-generated", + "providerId" : "rsa-enc-generated", + "subComponents" : { }, + "config" : { + "privateKey" : [ "MIIEogIBAAKCAQEAudnbEbQij+g9JWYMuyJjF/sKe4fVEd9SrCmkFeAHZ7dEAmEKQcAlvJn1aL99pAm8KV0w9PAZugQx7ZzG6eUm4JLc+LYGJ8G8JDiVR6hIWRQ3k9HGcUwNacHKFlDj4XOeMykwLEo7jrQHAUx82vJO8bKZr2ixZqGc1UUUQNbEVYv0HzxhPKPoFYh9qQ8U6P0r/K9xIusLL6ZzmXx6uXqQuqtse05e5G9xwLjQDDrOKju4s1PJ1GZLt5Db9PGypMeA9J34tGL3O0rQom2WbO7R2GZGX044ZoNw6UnraGTmCxin1ywmwTq3JTb1IZ4DPLH/rucnPuKUb60B5ByPmXW/lQIDAQABAoIBAAlyYrGLbb9RX3xNa+O+O3m+U7nUPXcfWikwo6vN+6pgtScGzjnp3bEwxTnqE+WY7hTPLRwiMTiUmoIYuD6u3HNJW8yTmgv+y8SukJ34FpdakPmlTdg39K2VwWMxgOfWk+nHU/DIZC8chQeinu0VKICeIrQ5Ft1f5SQtEvq5v/iWIql+v2ipxdJ2dSl1NIO0/2S2Lyd7Slab50gbJ3kP0uZggN5IMtNd5GBvAbV+jaT4QWKuyXyHqOnyU/+2WU+XhmVPrX6c29sQg2CilqWf4RzEIeO/FgAiANEPyaAgW6mGtf17K1xsSrusyGMUsNGsGJSd7Q8K2o7g/Jv9V8160iECgYEA2xgKIoZ6+fT7UIDr+5insRr6PIht2WYl+JqibjzNRh+rvp1fjKkmjMOA39V6cvLaAHieSOUerSOD7nQONCedpHe6To1zOG9z5yYGgwa/2c/9eNORJq8vNw/4wXaARVf0mCNaexugPTdYvsSaqwW4+azIbB21xXUfKykLp0SjNfUCgYEA2ShJSZyTIqJ64IHi+Kj/E22ajK2DYBiFgNDmzKrW/ANO5ADumgMhahCcxW28Nw68n25vBWCK4o+6eVg1ldEdB1LxoKOYZAaA+zAiMsGI1/ndxdnlFopuJZguKhYDTmxzT0KcD9mApLKZBnCadGjG3FcdC8i14OK6S9lUIIpCvyECgYBXqWC0u7YMuPatGUhSXJwMAs1I1xWMvJBIziZbkTxY6GchV3pZn3xrKfYwmQvrXjvXoGtEo1gI0oMBL7JXL9qlabpDn9kQJZfsToygdFzi25OBerVDEykDEQLo9W8RT8Xv8YVMaJtOowyBF80CzMFcNMPkbmbCYMBd1ohxHsdm2QKBgGB9RhMvPzFkgLTBAdj7Plujl8hqULWiL6/NIsBOKLhRv/wPbfWA7pfySbZvy/Gq2qT8rNf2zb9dnb3NNAIdqIhYkoSOLGhFe4ohGRD0bZmJrMD80I3zdH2/4MNShKWUCqhtMGraeg60TMpPvlF7POEq0/0ocag7FgwdxQOwa3gBAoGASvjvVtfXyzWA9MycWLvlTPEGW5bjXrroYwulF8DkKfIaKWHfEiulTwQe4SHgS7CzWSg8KgvKIhJC/yTwfOtxZ894G9LWivwjjZCottIE+/qs6ioYSXouQr6IsWxs7U0i3gP36tsePjuSjR06kpBGfcFdynypAAq+mVBCV0Mxk9A=" ], + "keyUse" : [ "ENC" ], + "certificate" : [ "MIICnTCCAYUCBgGVU7avyzANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAd0ZWFjaGVyMB4XDTI1MDMwMTIxNTUzNloXDTM1MDMwMTIxNTcxNlowEjEQMA4GA1UEAwwHdGVhY2hlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALnZ2xG0Io/oPSVmDLsiYxf7CnuH1RHfUqwppBXgB2e3RAJhCkHAJbyZ9Wi/faQJvCldMPTwGboEMe2cxunlJuCS3Pi2BifBvCQ4lUeoSFkUN5PRxnFMDWnByhZQ4+FznjMpMCxKO460BwFMfNryTvGyma9osWahnNVFFEDWxFWL9B88YTyj6BWIfakPFOj9K/yvcSLrCy+mc5l8erl6kLqrbHtOXuRvccC40Aw6zio7uLNTydRmS7eQ2/TxsqTHgPSd+LRi9ztK0KJtlmzu0dhmRl9OOGaDcOlJ62hk5gsYp9csJsE6tyU29SGeAzyx/67nJz7ilG+tAeQcj5l1v5UCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAf3HTufrfWb0uqsEwfUETl4S4IbJOjqDdzFhUkMVtiq5I9LLUlJ7StZ6eoDCEoKUzF2lPy0qR2Om7IKC8BA7J5qUio0NSNh9j/t1Ipcjzx6SQI2cD6AjJFZndnF+OBTxdm9c6J+KMho6ZSMQEGwn2osgRBeItauxUshogQJPY/GzWMHlZyCAJcYtuflzgyw1VIQ0OiWCpCiSGeWpojxh19KR9qSBU1rETZMLokmdp84muq8aqEnNIFY5XRyUdH4gjNBx3TGsammZbvzuZdZIDvFNE19SXl/J9QcWJlRw0DuOblLcLKiamcJkQj35T9DgwtYRc/2zM3u8jNwQXKwrUWA==" ], + "priority" : [ "100" ], + "algorithm" : [ "RSA-OAEP" ] + } + }, { + "id" : "ce5dcd75-614d-453a-868c-4413b4a10c39", + "name" : "hmac-generated-hs512", + "providerId" : "hmac-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "a58f2df5-d24b-4aae-9e38-d42736883c7d" ], + "secret" : [ "4sDZ4TC6Cuo0-A5Wa42n_HLCxFj6ir4enL6OmdllOTtR7f5YJN5bsPOJXOFGHeuNPe5jgNq2GfOaeqyQ19PnJMd3Ctsj7vQlx57hywXNvQ1FNuKL1uoxF2Szvw65Y4gIM7xoZpQglVhg2Zh7kA3HJEVhDvnmjNdjtm1QgdlFYws" ], + "priority" : [ "100" ], + "algorithm" : [ "HS512" ] + } + }, { + "id" : "972a70cc-5e9d-4435-8423-f4d32e18d1e7", + "name" : "rsa-generated", + "providerId" : "rsa-generated", + "subComponents" : { }, + "config" : { + "privateKey" : [ "MIIEogIBAAKCAQEAy3EHaNAy6udZMC3A2KIZhMDg0SfGN+FVOKRJfh6aJwtNPuP6EXUhCMRSCXj3EHvFYrBJwKllC8li8MC5rw0vF/P9OY1zdbNkg8Rpwa1D55AS/MlYqiKHazKIV55SXVt5MKtjGATk9D4P/UZ8iP3viBnT0Kws4lWrAv1Uk12CkeLzojeTdCr4I8xgsj5U6dWu2f9DJlsieBhefgJpIXgdWXzVyGC3dOQOrCMHxYdyL4dbBlJPk13QJGkmgH65PnRB0Zu4CtlNHWN1jbXWcRNs8iMLZ4R36F8OzbMcv51lv7+0UTP7HJ4iRjw+sSlUH1AB+3sklyoNgRnW6sisEA+UFQIDAQABAoIBAA9kbWGWQwv31g0poQoi9ZhQOZJJlps6vsZq066ppRMoLT+BYzW37Xhq1iQmVVcXbj9BxErB5kXGhmhdxI7EihgfWzzkAWTZ3lSD41aGg/k8stsSZtV0iFdpetxaO7QZjClNBlHWaPY7zdzlXN3GjL146shChqDXR3mR7ji6HftolGVnmzUXRK+gZG9IirlC+qCJ+sd6m9h83x31X5PRT6yiJ/jeNN4XpuMh61xHFckFOFCGfV2isWM9qL5kLllN1+m8nMjt0HOeEB0GRrHTMSp7QC9RI0z1C/uxdAdSyMhCUtva8jAfjtqYAo7yc63zlOvlkFuYeOQ9X8UmnavBbL8CgYEA7FjyjVr3OK139528/FJMmLk2xOCDQ08pS+ADX5Eib7R62k1ZzXiKnv/8whfdQFeJwIunSYn+y2JCaMFjARrh04SELeH6/CvQ5uCknfIkLeNBij1ye5Ruy7JpaV3oe36h8sJYv1+p5RcrxxINBxbEeKM/YQWRwcXVE54MBCB4dKsCgYEA3FufmasbB4Pna2Txlgo+XCKpf+1U+gcN6lRzsKzqtFVT7+ofUndnqTKgPrLHYytYOFIZIIP8YZBno5gUvK7bFjgAGWacayYNWAXSiEhRQ3ah95Ii/b4lcU095GN/Xu68yqlGQc0GDVD9xRejBNyYgHc2GPQ9bigjsb6pQLy0mj8CgYAN5SjVcKyqM2CjOS3cM8Z3ECSNLJnrAiNuZ4wrOTAqGxVB8lw+PUEBGhG1I4wJdVwO6ub55tgJAwzedcgpT3hJZDgVLn0ACF9uw3RKKOtBm2PGCdjKNS7SYPnbjP7XC9nfmNd44NnvMw6K1J/Zc9g3M3nNbXNlTgk57wfL0lDiowKBgEIF4cf1EGAsEUaINCo0X4LTj92YioFvY6f2LcOdy6TEfCXCDCh1RkXXuVOP1VXNQt19G7I2WYQR9Dt78Zqm+VWq6byyleM0v4LEG9Rhdpe0D8tRqdJFCorsDcNEXIFhHofKOBa3Cz0qKx7Gej2Wqsqy7S6E33MF68vxyFxxLduZAoGAcHhDa8r7EMFTEt3rZIqmblqOYvhfMKJ+Ruom11mUSHWLgyQGzK8mVPhB59J7gt0DKU6XRIwby/7c7x2wFWQ+dsy03PN49PDtewLcGtrsicJlY2mofFZpsFsYhOpyhPg4/zFiX77Ev3UEYiJJ4qXnlV5Yb+ae5D8ZNlmhIP1HQY4=" ], + "keyUse" : [ "SIG" ], + "certificate" : [ "MIICnTCCAYUCBgGVU7avAzANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAd0ZWFjaGVyMB4XDTI1MDMwMTIxNTUzNloXDTM1MDMwMTIxNTcxNlowEjEQMA4GA1UEAwwHdGVhY2hlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMtxB2jQMurnWTAtwNiiGYTA4NEnxjfhVTikSX4emicLTT7j+hF1IQjEUgl49xB7xWKwScCpZQvJYvDAua8NLxfz/TmNc3WzZIPEacGtQ+eQEvzJWKoih2syiFeeUl1beTCrYxgE5PQ+D/1GfIj974gZ09CsLOJVqwL9VJNdgpHi86I3k3Qq+CPMYLI+VOnVrtn/QyZbIngYXn4CaSF4HVl81chgt3TkDqwjB8WHci+HWwZST5Nd0CRpJoB+uT50QdGbuArZTR1jdY211nETbPIjC2eEd+hfDs2zHL+dZb+/tFEz+xyeIkY8PrEpVB9QAft7JJcqDYEZ1urIrBAPlBUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAHkOqsY1iHqqCMDFvTh/XCNZRwdLdGY6ev+5zShrgb8MPJNgM/HIqQtwQ9wuKf5RfMF1+FQdSU1eavTeuHXp4IuMgv97DAjdZ/pBGHz5tCWMdlaf+Au/1zDoqCV91CbGuV6WHaUhDJLZfp9/phiq2BzPZO6LeWhFJLMzH+N6rPZ7Om72rjTN31TlLLgmLuKlOhMp2QpyaQB16g4ksLGIYq7IXIbCqPRuB33k3gO/+ZMYRpU2U4DQ3FZyIe4LzLXQQ7VSFz/x/rvnbF+hHBdcbszUvsQYCS21aZ6nAq4CGinU2iAOLXHmFotKs+01KZT1N3ZGlGQmHM8ywYyb9qbcfPA==" ], + "priority" : [ "100" ] + } + }, { + "id" : "24e3094f-f962-49bd-b355-ff3096bfefe8", + "name" : "aes-generated", + "providerId" : "aes-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "52ac32c1-f589-4e04-9667-16d2e7bd707a" ], + "secret" : [ "ZEiWoUCZ30PSKa2rx8UXTQ" ], + "priority" : [ "100" ] + } + } ] + }, + "internationalizationEnabled" : false, + "supportedLocales" : [ ], + "authenticationFlows" : [ { + "id" : "2ac7aebb-c1ac-4fdf-9687-cedd34665024", + "alias" : "Account verification options", + "description" : "Method with which to verity the existing account", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-email-verification", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Verify Existing Account by Re-authentication", + "userSetupAllowed" : false + } ] + }, { + "id" : "2505f3dc-719b-43a1-9631-585302dd449e", + "alias" : "Browser - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "auth-otp-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "5a07c120-c34b-4cf2-b38d-2e558af6853a", + "alias" : "Browser - Conditional Organization", + "description" : "Flow to determine if the organization identity-first login is to be used", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "organization", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "a3317f52-b2bc-4b4c-af14-53901d253fca", + "alias" : "Direct Grant - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "direct-grant-validate-otp", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "2281818c-fb40-4997-a1ad-fc9ad2c3cacc", + "alias" : "First Broker Login - Conditional Organization", + "description" : "Flow to determine if the authenticator that adds organization members is to be used", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "idp-add-organization-member", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "fcab0380-ca38-4f66-aaf2-ec741ef8be8e", + "alias" : "First broker login - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "auth-otp-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "ae2e214a-82b6-4d78-a7d0-f80d454e5083", + "alias" : "Handle Existing Account", + "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-confirm-link", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Account verification options", + "userSetupAllowed" : false + } ] + }, { + "id" : "ad2add46-e1bb-47bf-a125-d76c517f66a4", + "alias" : "Organization", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 10, + "autheticatorFlow" : true, + "flowAlias" : "Browser - Conditional Organization", + "userSetupAllowed" : false + } ] + }, { + "id" : "74e5d429-4db2-4323-b504-005c03e530fc", + "alias" : "Reset - Conditional OTP", + "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "reset-otp", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "d11dbfe7-2472-4cda-a7f5-e9a536154028", + "alias" : "User creation or linking", + "description" : "Flow for the existing/non-existing user alternatives", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticatorConfig" : "create unique user config", + "authenticator" : "idp-create-user-if-unique", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Handle Existing Account", + "userSetupAllowed" : false + } ] + }, { + "id" : "f1131dc8-ea34-48e1-9363-438c15f985a4", + "alias" : "Verify Existing Account by Re-authentication", + "description" : "Reauthentication of existing account", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-username-password-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "First broker login - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "f2880986-ef01-4199-ac31-35e0b16c989b", + "alias" : "browser", + "description" : "Browser based authentication", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "auth-cookie", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "auth-spnego", + "authenticatorFlow" : false, + "requirement" : "DISABLED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "identity-provider-redirector", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 25, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 26, + "autheticatorFlow" : true, + "flowAlias" : "Organization", + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 30, + "autheticatorFlow" : true, + "flowAlias" : "forms", + "userSetupAllowed" : false + } ] + }, { + "id" : "a08dca2e-d491-483f-a310-25bcfa2d89b3", + "alias" : "clients", + "description" : "Base authentication for clients", + "providerId" : "client-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "client-secret", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "client-jwt", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "client-secret-jwt", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 30, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "client-x509", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 40, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "4742ab83-03c9-417d-ba61-017d9f02afb3", + "alias" : "direct grant", + "description" : "OpenID Connect Resource Owner Grant", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "direct-grant-validate-username", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "direct-grant-validate-password", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 30, + "autheticatorFlow" : true, + "flowAlias" : "Direct Grant - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "458f78fd-84e5-4e4d-8198-200f25942134", + "alias" : "docker auth", + "description" : "Used by Docker clients to authenticate against the IDP", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "docker-http-basic-authenticator", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "8cbdd82f-3794-4fce-9494-70279a3d1fcb", + "alias" : "first broker login", + "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticatorConfig" : "review profile config", + "authenticator" : "idp-review-profile", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "User creation or linking", + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 50, + "autheticatorFlow" : true, + "flowAlias" : "First Broker Login - Conditional Organization", + "userSetupAllowed" : false + } ] + }, { + "id" : "b64919c6-da2b-4e66-bcc6-0112d9e3132b", + "alias" : "forms", + "description" : "Username, password, otp and other auth forms.", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "auth-username-password-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Browser - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "3c8979fe-c98c-4911-b16c-510dba8fb8e3", + "alias" : "registration", + "description" : "Registration flow", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "registration-page-form", + "authenticatorFlow" : true, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : true, + "flowAlias" : "registration form", + "userSetupAllowed" : false + } ] + }, { + "id" : "6f598384-bb66-485e-8ed5-7da83c1deba1", + "alias" : "registration form", + "description" : "Registration form", + "providerId" : "form-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "registration-user-creation", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "registration-password-action", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 50, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "registration-recaptcha-action", + "authenticatorFlow" : false, + "requirement" : "DISABLED", + "priority" : 60, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "registration-terms-and-conditions", + "authenticatorFlow" : false, + "requirement" : "DISABLED", + "priority" : 70, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "086acb80-23bb-496d-a982-0d8886b2e844", + "alias" : "reset credentials", + "description" : "Reset credentials for a user if they forgot their password or something", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "reset-credentials-choose-user", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "reset-credential-email", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "reset-password", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 30, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 40, + "autheticatorFlow" : true, + "flowAlias" : "Reset - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "2b5042d2-f5e2-456c-bd94-1f23ea0bfb20", + "alias" : "saml ecp", + "description" : "SAML ECP Profile Authentication Flow", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "http-basic-authenticator", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + } ], + "authenticatorConfig" : [ { + "id" : "3007c3b0-cdd5-4464-93f4-23e439b15253", + "alias" : "create unique user config", + "config" : { + "require.password.update.after.registration" : "false" + } + }, { + "id" : "ce14faa0-34fe-496f-bcb5-a7e72fcf3fbb", + "alias" : "review profile config", + "config" : { + "update.profile.on.first.login" : "missing" + } + } ], + "requiredActions" : [ { + "alias" : "CONFIGURE_TOTP", + "name" : "Configure OTP", + "providerId" : "CONFIGURE_TOTP", + "enabled" : true, + "defaultAction" : false, + "priority" : 10, + "config" : { } + }, { + "alias" : "TERMS_AND_CONDITIONS", + "name" : "Terms and Conditions", + "providerId" : "TERMS_AND_CONDITIONS", + "enabled" : false, + "defaultAction" : false, + "priority" : 20, + "config" : { } + }, { + "alias" : "UPDATE_PASSWORD", + "name" : "Update Password", + "providerId" : "UPDATE_PASSWORD", + "enabled" : true, + "defaultAction" : false, + "priority" : 30, + "config" : { } + }, { + "alias" : "UPDATE_PROFILE", + "name" : "Update Profile", + "providerId" : "UPDATE_PROFILE", + "enabled" : true, + "defaultAction" : false, + "priority" : 40, + "config" : { } + }, { + "alias" : "VERIFY_EMAIL", + "name" : "Verify Email", + "providerId" : "VERIFY_EMAIL", + "enabled" : true, + "defaultAction" : false, + "priority" : 50, + "config" : { } + }, { + "alias" : "delete_account", + "name" : "Delete Account", + "providerId" : "delete_account", + "enabled" : false, + "defaultAction" : false, + "priority" : 60, + "config" : { } + }, { + "alias" : "webauthn-register", + "name" : "Webauthn Register", + "providerId" : "webauthn-register", + "enabled" : true, + "defaultAction" : false, + "priority" : 70, + "config" : { } + }, { + "alias" : "webauthn-register-passwordless", + "name" : "Webauthn Register Passwordless", + "providerId" : "webauthn-register-passwordless", + "enabled" : true, + "defaultAction" : false, + "priority" : 80, + "config" : { } + }, { + "alias" : "VERIFY_PROFILE", + "name" : "Verify Profile", + "providerId" : "VERIFY_PROFILE", + "enabled" : true, + "defaultAction" : false, + "priority" : 90, + "config" : { } + }, { + "alias" : "delete_credential", + "name" : "Delete Credential", + "providerId" : "delete_credential", + "enabled" : true, + "defaultAction" : false, + "priority" : 100, + "config" : { } + }, { + "alias" : "update_user_locale", + "name" : "Update User Locale", + "providerId" : "update_user_locale", + "enabled" : true, + "defaultAction" : false, + "priority" : 1000, + "config" : { } + } ], + "browserFlow" : "browser", + "registrationFlow" : "registration", + "directGrantFlow" : "direct grant", + "resetCredentialsFlow" : "reset credentials", + "clientAuthenticationFlow" : "clients", + "dockerAuthenticationFlow" : "docker auth", + "firstBrokerLoginFlow" : "first broker login", + "attributes" : { + "cibaBackchannelTokenDeliveryMode" : "poll", + "cibaExpiresIn" : "120", + "cibaAuthRequestedUserHint" : "login_hint", + "oauth2DeviceCodeLifespan" : "600", + "oauth2DevicePollingInterval" : "5", + "parRequestUriLifespan" : "60", + "cibaInterval" : "5", + "realmReusableOtpCode" : "false" + }, + "keycloakVersion" : "26.1.3", + "userManagedAccessAllowed" : false, + "organizationsEnabled" : false, + "verifiableCredentialsEnabled" : false, + "adminPermissionsEnabled" : false, + "clientProfiles" : { + "profiles" : [ ] + }, + "clientPolicies" : { + "policies" : [ ] + } +} From e6c03c1acaa216f5dc3115a45506700bab49f4fa Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Sun, 2 Mar 2025 13:58:08 +0100 Subject: [PATCH 028/180] chore(backend): Definieer logger voor MikroORM Maak gebruik van juiste logging niveau voor elke taak (namespace) --- backend/src/logging/mikroOrmLogger.ts | 88 +++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 backend/src/logging/mikroOrmLogger.ts diff --git a/backend/src/logging/mikroOrmLogger.ts b/backend/src/logging/mikroOrmLogger.ts new file mode 100644 index 00000000..4fbadb96 --- /dev/null +++ b/backend/src/logging/mikroOrmLogger.ts @@ -0,0 +1,88 @@ +import { DefaultLogger, LogContext, LoggerNamespace } from '@mikro-orm/core'; +import { Logger } from 'winston'; +import { getLogger } from './initalize'; +import { LokiLabels } from 'loki-logger-ts'; + +export class MikroOrmLogger extends DefaultLogger { + private logger: Logger = getLogger(); + + log(namespace: LoggerNamespace, message: string, context?: LogContext) { + if (!this.isEnabled(namespace, context)) { + return; + } + + switch (namespace) { + case 'query': + this.logger.debug( + this.createMessage(namespace, message, context) + ); + break; + case 'query-params': + // TODO Which log level should this be? + this.logger.info( + this.createMessage(namespace, message, context) + ); + break; + case 'schema': + this.logger.info( + this.createMessage(namespace, message, context) + ); + break; + case 'discovery': + this.logger.debug( + this.createMessage(namespace, message, context) + ); + break; + case 'info': + this.logger.info( + this.createMessage(namespace, message, context) + ); + break; + case 'deprecated': + this.logger.warn( + this.createMessage(namespace, message, context) + ); + break; + default: + switch (context?.level) { + case 'info': + this.logger.info( + this.createMessage(namespace, message, context) + ); + break; + case 'warning': + this.logger.warn(message); + break; + case 'error': + this.logger.error(message); + break; + default: + this.logger.debug(message); + break; + } + } + } + + private createMessage( + namespace: LoggerNamespace, + messageArg: string, + context?: LogContext + ) { + const labels: LokiLabels = { + service: 'ORM', + }; + + let message: string; + if (context?.label) { + message = `[${namespace}] (${context?.label}) ${messageArg}`; + } else { + message = `[${namespace}] ${messageArg}`; + } + + return { + message: message, + labels: labels, + context: context, + }; + } +} From eca8d897122021a1f3054f4e9446344900aebdcf Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Sun, 2 Mar 2025 13:59:38 +0100 Subject: [PATCH 029/180] chore(backend): Duidelijkere MikroORM logging Zorgt voor beter formaat en juiste labels --- backend/.env.example | 12 +++++++++++- backend/src/config.ts | 6 ++++++ backend/src/logging/initalize.ts | 20 +++++++++++--------- backend/src/logging/responseTimeLogger.ts | 1 - backend/src/mikro-orm.config.ts | 12 ++++++++++-- 5 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 backend/src/config.ts diff --git a/backend/.env.example b/backend/.env.example index c0c68b1c..165b7a29 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -1 +1,11 @@ -PORT=3000 \ No newline at end of file +# +# Basic configuration +# + +PORT=3000 # The port the backend will listen on + +# +# Advanced configuration +# + +# LOKI_HOST=http://localhost:3102 # The address of the Loki instance, used for logging diff --git a/backend/src/config.ts b/backend/src/config.ts new file mode 100644 index 00000000..9edd1437 --- /dev/null +++ b/backend/src/config.ts @@ -0,0 +1,6 @@ +// Logging + +export const LOG_LEVEL: string = + 'development' === process.env.NODE_ENV ? 'debug' : 'info'; +export const LOKI_HOST: string = + process.env.LOKI_HOST || 'http://localhost:3102'; diff --git a/backend/src/logging/initalize.ts b/backend/src/logging/initalize.ts index 6a4d52c5..5da786fe 100644 --- a/backend/src/logging/initalize.ts +++ b/backend/src/logging/initalize.ts @@ -1,43 +1,45 @@ import { createLogger, format, Logger, transports } from 'winston'; import LokiTransport from 'winston-loki'; import { LokiLabels } from 'loki-logger-ts'; +import { LOG_LEVEL, LOKI_HOST } from '../config.js'; -const LoggingLevel = 'development' === process.env.NODE_ENV ? 'debug' : 'info'; -const Host = 'http://localhost:3102'; const Labels: LokiLabels = { source: 'Dwengo-Backend', - job: 'Dwengo-Backend', + service: 'API', host: 'localhost', }; let logger: Logger; -function initializeLogger() { +function initializeLogger(): Logger { if (logger !== undefined) { return logger; } const lokiTransport: LokiTransport = new LokiTransport({ - host: Host, + host: LOKI_HOST, labels: Labels, - level: LoggingLevel, + level: LOG_LEVEL, json: true, format: format.combine(format.timestamp(), format.json()), onConnectionError: (err) => { + // eslint-disable-next-line no-console console.error(`Connection error: ${err}`); }, }); const consoleTransport = new transports.Console({ - level: LoggingLevel, - format: format.combine(format.simple(), format.colorize()), + level: LOG_LEVEL, + format: format.combine(format.cli(), format.colorize()), }); logger = createLogger({ transports: [lokiTransport, consoleTransport], }); - logger.debug('Logger initialized'); + logger.debug( + `Logger initialized with level ${LOG_LEVEL}, Loki host ${LOKI_HOST}` + ); return logger; } diff --git a/backend/src/logging/responseTimeLogger.ts b/backend/src/logging/responseTimeLogger.ts index 5baf63f4..85723e5e 100644 --- a/backend/src/logging/responseTimeLogger.ts +++ b/backend/src/logging/responseTimeLogger.ts @@ -16,7 +16,6 @@ export function responseTimeLogger(req: Request, res: Response, time: number) { status: status, responseTime: Number(time), labels: { - origin: 'api', type: 'responseTime', }, }); diff --git a/backend/src/mikro-orm.config.ts b/backend/src/mikro-orm.config.ts index c4302a37..1beec07b 100644 --- a/backend/src/mikro-orm.config.ts +++ b/backend/src/mikro-orm.config.ts @@ -1,12 +1,20 @@ -import { Options } from '@mikro-orm/core'; +import { LoggerOptions, Options } from '@mikro-orm/core'; import { PostgreSqlDriver } from '@mikro-orm/postgresql'; +import { MikroOrmLogger } from './logging/mikroOrmLogger.js'; +import { LOG_LEVEL } from './config.js'; const config: Options = { driver: PostgreSqlDriver, dbName: 'dwengo', + password: 'postgres', entities: ['dist/**/*.entity.js'], entitiesTs: ['src/**/*.entity.ts'], - debug: true, + + // Logging + debug: LOG_LEVEL === 'debug', + loggerFactory: (options: LoggerOptions) => { + return new MikroOrmLogger(options); + }, }; export default config; From ebf741a0d0e65580b52867f405457bab4dd3e31c Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Sun, 2 Mar 2025 14:08:21 +0100 Subject: [PATCH 030/180] fix(backend): Ontbrekende .js in imports --- backend/src/logging/mikroOrmLogger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/logging/mikroOrmLogger.ts b/backend/src/logging/mikroOrmLogger.ts index 4fbadb96..49818427 100644 --- a/backend/src/logging/mikroOrmLogger.ts +++ b/backend/src/logging/mikroOrmLogger.ts @@ -1,6 +1,6 @@ import { DefaultLogger, LogContext, LoggerNamespace } from '@mikro-orm/core'; import { Logger } from 'winston'; -import { getLogger } from './initalize'; +import { getLogger } from './initalize.js'; import { LokiLabels } from 'loki-logger-ts'; export class MikroOrmLogger extends DefaultLogger { From 4b40653a1c0962e67ccf5fe53b818e07c8dd66ef Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Sun, 2 Mar 2025 14:10:31 +0100 Subject: [PATCH 031/180] fix(backend): Verander Grafana poort Verander grafana poort naar 3100 om conflict met standaard poort 3000 van backend te vermijden. --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 1f8a4c98..a348d23d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,7 +25,7 @@ services: dashboards: image: grafana/grafana:latest ports: - - '3000:3000' + - '3100:3000' volumes: - dwengo_grafana_data:/var/lib/grafana restart: unless-stopped From c2e3886f3f10ea01551b3c1cef7f3668ab6ab462 Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Sun, 2 Mar 2025 15:14:26 +0100 Subject: [PATCH 032/180] chore(backend): Switch console naar logger Maak gebruik van custom logger --- backend/src/controllers/learningObjects.ts | 5 +++-- backend/src/controllers/learningPaths.ts | 3 ++- backend/src/controllers/themes.ts | 8 ++++++-- backend/src/services/learningObjects.ts | 10 +++++++--- backend/src/services/learningPaths.ts | 6 +++++- backend/src/util/apiHelper.ts | 10 ++++++---- 6 files changed, 29 insertions(+), 13 deletions(-) diff --git a/backend/src/controllers/learningObjects.ts b/backend/src/controllers/learningObjects.ts index 4295326a..90cd3f13 100644 --- a/backend/src/controllers/learningObjects.ts +++ b/backend/src/controllers/learningObjects.ts @@ -6,6 +6,7 @@ import { } from '../services/learningObjects.js'; import { FALLBACK_LANG } from '../config.js'; import { FilteredLearningObject } from '../interfaces/learningPath'; +import { getLogger } from '../logging/initalize'; export async function getAllLearningObjects( req: Request, @@ -33,7 +34,7 @@ export async function getAllLearningObjects( res.json(learningObjects); } catch (error) { - console.error('Error fetching learning objects:', error); + getLogger().error('Error fetching learning objects:', error); res.status(500).json({ error: 'Internal server error' }); } } @@ -54,7 +55,7 @@ export async function getLearningObject( const learningObject = await getLearningObjectById(hruid, language); res.json(learningObject); } catch (error) { - console.error('Error fetching learning object:', error); + getLogger().error('Error fetching learning object:', error); res.status(500).json({ error: 'Internal server error' }); } } diff --git a/backend/src/controllers/learningPaths.ts b/backend/src/controllers/learningPaths.ts index 903451be..86878bfd 100644 --- a/backend/src/controllers/learningPaths.ts +++ b/backend/src/controllers/learningPaths.ts @@ -5,6 +5,7 @@ import { fetchLearningPaths, searchLearningPaths, } from '../services/learningPaths.js'; +import { getLogger } from '../logging/initalize.js'; /** * Fetch learning paths based on query parameters. */ @@ -56,7 +57,7 @@ export async function getLearningPaths( ); res.json(learningPaths.data); } catch (error) { - console.error('❌ Unexpected error fetching learning paths:', error); + getLogger().error('❌ Unexpected error fetching learning paths:', error); res.status(500).json({ error: 'Internal server error' }); } } diff --git a/backend/src/controllers/themes.ts b/backend/src/controllers/themes.ts index 817464ab..c10f1b98 100644 --- a/backend/src/controllers/themes.ts +++ b/backend/src/controllers/themes.ts @@ -1,9 +1,13 @@ import fs from 'fs'; import path from 'path'; import yaml from 'js-yaml'; +import { Logger } from 'winston'; import { Request, Response } from 'express'; import { themes } from '../data/themes.js'; import { FALLBACK_LANG } from '../config.js'; +import { getLogger } from '../logging/initalize.js'; + +const logger: Logger = getLogger(); interface Translations { curricula_page: { @@ -17,10 +21,10 @@ function loadTranslations(language: string): Translations { const yamlFile = fs.readFileSync(filePath, 'utf8'); return yaml.load(yamlFile) as Translations; } catch (error) { - console.error( + logger.error( `Cannot load translation for: ${language}, fallen back to Dutch` ); - console.error(error); + logger.error(error); const fallbackPath = path.join(process.cwd(), '_i18n', 'nl.yml'); return yaml.load(fs.readFileSync(fallbackPath, 'utf8')) as Translations; } diff --git a/backend/src/services/learningObjects.ts b/backend/src/services/learningObjects.ts index d1d34ad2..90370fe6 100644 --- a/backend/src/services/learningObjects.ts +++ b/backend/src/services/learningObjects.ts @@ -7,6 +7,10 @@ import { LearningPathResponse, } from '../interfaces/learningPath.js'; import { fetchLearningPaths } from './learningPaths.js'; +import { getLogger } from '../logging/initalize.js'; +import { Logger } from 'winston'; + +const logger: Logger = getLogger(); function filterData( data: LearningObjectMetadata, @@ -49,7 +53,7 @@ export async function getLearningObjectById( ); if (!metadata) { - console.error(`⚠️ WARNING: Learning object "${hruid}" not found.`); + logger.error(`⚠️ WARNING: Learning object "${hruid}" not found.`); return null; } @@ -77,7 +81,7 @@ async function fetchLearningObjects( !learningPathResponse.success || !learningPathResponse.data?.length ) { - console.error( + logger.error( `⚠️ WARNING: Learning path "${hruid}" exists but contains no learning objects.` ); return []; @@ -104,7 +108,7 @@ async function fetchLearningObjects( }); }); } catch (error) { - console.error('❌ Error fetching learning objects:', error); + logger.error('❌ Error fetching learning objects:', error); return []; } } diff --git a/backend/src/services/learningPaths.ts b/backend/src/services/learningPaths.ts index 2a9f15a3..7c445806 100644 --- a/backend/src/services/learningPaths.ts +++ b/backend/src/services/learningPaths.ts @@ -4,6 +4,10 @@ import { LearningPath, LearningPathResponse, } from '../interfaces/learningPath.js'; +import { getLogger } from '../logging/initalize.js'; +import { Logger } from 'winston'; + +const logger: Logger = getLogger(); export async function fetchLearningPaths( hruids: string[], @@ -29,7 +33,7 @@ export async function fetchLearningPaths( ); if (!learningPaths || learningPaths.length === 0) { - console.error(`⚠️ WARNING: No learning paths found for ${source}.`); + logger.error(`⚠️ WARNING: No learning paths found for ${source}.`); return { success: false, source, diff --git a/backend/src/util/apiHelper.ts b/backend/src/util/apiHelper.ts index 76d166c8..4a1cae7f 100644 --- a/backend/src/util/apiHelper.ts +++ b/backend/src/util/apiHelper.ts @@ -1,6 +1,8 @@ import axios, { AxiosRequestConfig } from 'axios'; +import { getLogger } from '../logging/initalize.js'; +import { Logger } from 'winston'; -// !!!! when logger is done -> change +const logger: Logger = getLogger(); /** * Utility function to fetch data from an API endpoint with error handling. @@ -24,16 +26,16 @@ export async function fetchWithLogging( } catch (error: any) { if (error.response) { if (error.response.status === 404) { - console.error( + logger.error( `❌ ERROR: ${description} not found (404) at "${url}".` ); } else { - console.error( + logger.error( `❌ ERROR: Failed to fetch ${description}. Status: ${error.response.status} - ${error.response.statusText} (URL: "${url}")` ); } } else { - console.error( + logger.error( `❌ ERROR: Network or unexpected error when fetching ${description}:`, error.message ); From c37d4d8e0437daa0b8f0f01b0a7e759dc3d8b65e Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Sun, 2 Mar 2025 15:20:57 +0100 Subject: [PATCH 033/180] chore(backend): Export Logger class --- backend/src/app.ts | 3 +-- backend/src/controllers/themes.ts | 3 +-- backend/src/logging/initalize.ts | 13 ++++++++++++- backend/src/logging/mikroOrmLogger.ts | 3 +-- backend/src/logging/responseTimeLogger.ts | 3 +-- backend/src/orm.ts | 3 +-- backend/src/services/learningObjects.ts | 3 +-- backend/src/services/learningPaths.ts | 8 ++------ backend/src/util/apiHelper.ts | 3 +-- 9 files changed, 21 insertions(+), 21 deletions(-) diff --git a/backend/src/app.ts b/backend/src/app.ts index 2161666f..652c27d1 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -12,10 +12,9 @@ import submissionRouter from './routes/submission.js'; import classRouter from './routes/class.js'; import questionRouter from './routes/question.js'; import loginRouter from './routes/login.js'; -import { getLogger } from './logging/initalize.js'; +import { getLogger, Logger } from './logging/initalize.js'; import { responseTimeLogger } from './logging/responseTimeLogger.js'; import responseTime from 'response-time'; -import { Logger } from 'winston'; import { EnvVars, getNumericEnvVar } from './util/envvars.js'; const logger: Logger = getLogger(); diff --git a/backend/src/controllers/themes.ts b/backend/src/controllers/themes.ts index c10f1b98..e60502ed 100644 --- a/backend/src/controllers/themes.ts +++ b/backend/src/controllers/themes.ts @@ -1,11 +1,10 @@ import fs from 'fs'; import path from 'path'; import yaml from 'js-yaml'; -import { Logger } from 'winston'; import { Request, Response } from 'express'; import { themes } from '../data/themes.js'; import { FALLBACK_LANG } from '../config.js'; -import { getLogger } from '../logging/initalize.js'; +import { getLogger, Logger } from '../logging/initalize.js'; const logger: Logger = getLogger(); diff --git a/backend/src/logging/initalize.ts b/backend/src/logging/initalize.ts index 5da786fe..18166408 100644 --- a/backend/src/logging/initalize.ts +++ b/backend/src/logging/initalize.ts @@ -1,8 +1,19 @@ -import { createLogger, format, Logger, transports } from 'winston'; +import { + createLogger, + format, + Logger as WinstonLogger, + transports, +} from 'winston'; import LokiTransport from 'winston-loki'; import { LokiLabels } from 'loki-logger-ts'; import { LOG_LEVEL, LOKI_HOST } from '../config.js'; +export class Logger extends WinstonLogger { + constructor() { + super(); + } +} + const Labels: LokiLabels = { source: 'Dwengo-Backend', service: 'API', diff --git a/backend/src/logging/mikroOrmLogger.ts b/backend/src/logging/mikroOrmLogger.ts index 49818427..e8bc1fad 100644 --- a/backend/src/logging/mikroOrmLogger.ts +++ b/backend/src/logging/mikroOrmLogger.ts @@ -1,6 +1,5 @@ import { DefaultLogger, LogContext, LoggerNamespace } from '@mikro-orm/core'; -import { Logger } from 'winston'; -import { getLogger } from './initalize.js'; +import { getLogger, Logger } from './initalize.js'; import { LokiLabels } from 'loki-logger-ts'; export class MikroOrmLogger extends DefaultLogger { diff --git a/backend/src/logging/responseTimeLogger.ts b/backend/src/logging/responseTimeLogger.ts index 85723e5e..c1bb1e33 100644 --- a/backend/src/logging/responseTimeLogger.ts +++ b/backend/src/logging/responseTimeLogger.ts @@ -1,5 +1,4 @@ -import { getLogger } from './initalize.js'; -import { Logger } from 'winston'; +import { getLogger, Logger } from './initalize.js'; import { Request, Response } from 'express'; export function responseTimeLogger(req: Request, res: Response, time: number) { diff --git a/backend/src/orm.ts b/backend/src/orm.ts index 2205fe89..88decd92 100644 --- a/backend/src/orm.ts +++ b/backend/src/orm.ts @@ -1,8 +1,7 @@ import { EntityManager, MikroORM } from '@mikro-orm/core'; import config from './mikro-orm.config.js'; import { EnvVars, getEnvVar } from './util/envvars.js'; -import { getLogger } from './logging/initalize.js'; -import { Logger } from 'winston'; +import { getLogger, Logger } from './logging/initalize.js'; let orm: MikroORM | undefined; export async function initORM(testingMode: boolean = false) { diff --git a/backend/src/services/learningObjects.ts b/backend/src/services/learningObjects.ts index 90370fe6..709c3298 100644 --- a/backend/src/services/learningObjects.ts +++ b/backend/src/services/learningObjects.ts @@ -7,8 +7,7 @@ import { LearningPathResponse, } from '../interfaces/learningPath.js'; import { fetchLearningPaths } from './learningPaths.js'; -import { getLogger } from '../logging/initalize.js'; -import { Logger } from 'winston'; +import { getLogger, Logger } from '../logging/initalize.js'; const logger: Logger = getLogger(); diff --git a/backend/src/services/learningPaths.ts b/backend/src/services/learningPaths.ts index 7c445806..58703215 100644 --- a/backend/src/services/learningPaths.ts +++ b/backend/src/services/learningPaths.ts @@ -1,11 +1,7 @@ import { fetchWithLogging } from '../util/apiHelper.js'; import { DWENGO_API_BASE } from '../config.js'; -import { - LearningPath, - LearningPathResponse, -} from '../interfaces/learningPath.js'; -import { getLogger } from '../logging/initalize.js'; -import { Logger } from 'winston'; +import { LearningPath, LearningPathResponse } from '../interfaces/learningPath.js'; +import { getLogger, Logger } from '../logging/initalize.js'; const logger: Logger = getLogger(); diff --git a/backend/src/util/apiHelper.ts b/backend/src/util/apiHelper.ts index 4a1cae7f..09492615 100644 --- a/backend/src/util/apiHelper.ts +++ b/backend/src/util/apiHelper.ts @@ -1,6 +1,5 @@ import axios, { AxiosRequestConfig } from 'axios'; -import { getLogger } from '../logging/initalize.js'; -import { Logger } from 'winston'; +import { getLogger, Logger } from '../logging/initalize.js'; const logger: Logger = getLogger(); From ddee299b4ab3a325abc19ced529abf9fa47d9b04 Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Sun, 2 Mar 2025 15:21:27 +0100 Subject: [PATCH 034/180] style(backend): Format --- backend/src/app.ts | 1 - backend/src/config.ts | 4 +- backend/src/controllers/learningPaths.ts | 5 ++- .../entities/assignments/assignment.entity.ts | 20 ++++++++-- .../src/entities/assignments/group.entity.ts | 13 ++++++- .../entities/assignments/submission.entity.ts | 20 ++++++++-- .../classes/class-join-request.entity.ts | 18 +++++++-- backend/src/entities/classes/class.entity.ts | 8 +++- .../classes/teacher-invitation.entity.ts | 21 ++++++++-- .../src/entities/content/attachment.entity.ts | 7 +++- .../content/learning-object.entity.ts | 33 +++++++++++++--- .../entities/content/learning-path.entity.ts | 39 ++++++++++++++++--- .../src/entities/questions/answer.entity.ts | 14 ++++++- .../src/entities/questions/question.entity.ts | 13 ++++++- backend/src/entities/users/student.entity.ts | 14 +++++-- backend/src/entities/users/teacher.entity.ts | 4 +- backend/src/routes/assignment.ts | 25 ++++-------- backend/src/routes/class.ts | 37 +++++++----------- backend/src/routes/group.ts | 21 +++++----- backend/src/routes/login.ts | 6 +-- backend/src/routes/question.ts | 24 +++++------- backend/src/routes/student.ts | 28 ++++++------- backend/src/routes/submission.ts | 11 ++---- backend/src/routes/teacher.ts | 24 ++++-------- backend/src/services/learningPaths.ts | 5 ++- 25 files changed, 265 insertions(+), 150 deletions(-) diff --git a/backend/src/app.ts b/backend/src/app.ts index 652c27d1..5769e360 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -22,7 +22,6 @@ const logger: Logger = getLogger(); const app: Express = express(); const port: string | number = getNumericEnvVar(EnvVars.Port); - app.use(express.json()); app.use(responseTime(responseTimeLogger)); diff --git a/backend/src/config.ts b/backend/src/config.ts index 831670a9..b972a1bd 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -7,6 +7,6 @@ export const DWENGO_API_BASE: string = 'https://dwengo.org/backend/api'; // Logging export const LOG_LEVEL: string = - 'development' === process.env.NODE_ENV ? 'debug' : 'info'; + 'development' === process.env.NODE_ENV ? 'debug' : 'info'; export const LOKI_HOST: string = - process.env.LOKI_HOST || 'http://localhost:3102'; + process.env.LOKI_HOST || 'http://localhost:3102'; diff --git a/backend/src/controllers/learningPaths.ts b/backend/src/controllers/learningPaths.ts index 86878bfd..247877e7 100644 --- a/backend/src/controllers/learningPaths.ts +++ b/backend/src/controllers/learningPaths.ts @@ -57,7 +57,10 @@ export async function getLearningPaths( ); res.json(learningPaths.data); } catch (error) { - getLogger().error('❌ Unexpected error fetching learning paths:', error); + getLogger().error( + '❌ Unexpected error fetching learning paths:', + error + ); res.status(500).json({ error: 'Internal server error' }); } } diff --git a/backend/src/entities/assignments/assignment.entity.ts b/backend/src/entities/assignments/assignment.entity.ts index 7909b107..89952c64 100644 --- a/backend/src/entities/assignments/assignment.entity.ts +++ b/backend/src/entities/assignments/assignment.entity.ts @@ -12,7 +12,12 @@ import { Language } from '../content/language.js'; @Entity() export class Assignment { - @ManyToOne({ entity: () => {return Class}, primary: true }) + @ManyToOne({ + entity: () => { + return Class; + }, + primary: true, + }) within!: Class; @PrimaryKey({ type: 'number' }) @@ -27,9 +32,18 @@ export class Assignment { @Property({ type: 'string' }) learningPathHruid!: string; - @Enum({ items: () => {return Language} }) + @Enum({ + items: () => { + return Language; + }, + }) learningPathLanguage!: Language; - @OneToMany({ entity: () => {return Group}, mappedBy: 'assignment' }) + @OneToMany({ + entity: () => { + return Group; + }, + mappedBy: 'assignment', + }) groups!: Group[]; } diff --git a/backend/src/entities/assignments/group.entity.ts b/backend/src/entities/assignments/group.entity.ts index a68eb5a0..5b224087 100644 --- a/backend/src/entities/assignments/group.entity.ts +++ b/backend/src/entities/assignments/group.entity.ts @@ -4,12 +4,21 @@ import { Student } from '../users/student.entity.js'; @Entity() export class Group { - @ManyToOne({ entity: () => {return Assignment}, primary: true }) + @ManyToOne({ + entity: () => { + return Assignment; + }, + primary: true, + }) assignment!: Assignment; @PrimaryKey({ type: 'integer' }) groupNumber!: number; - @ManyToMany({ entity: () => {return Student} }) + @ManyToMany({ + entity: () => { + return Student; + }, + }) members!: Student[]; } diff --git a/backend/src/entities/assignments/submission.entity.ts b/backend/src/entities/assignments/submission.entity.ts index bd0936a1..1bc28add 100644 --- a/backend/src/entities/assignments/submission.entity.ts +++ b/backend/src/entities/assignments/submission.entity.ts @@ -8,7 +8,12 @@ export class Submission { @PrimaryKey({ type: 'string' }) learningObjectHruid!: string; - @Enum({ items: () => {return Language}, primary: true }) + @Enum({ + items: () => { + return Language; + }, + primary: true, + }) learningObjectLanguage!: Language; @PrimaryKey({ type: 'string' }) @@ -17,13 +22,22 @@ export class Submission { @PrimaryKey({ type: 'integer' }) submissionNumber!: number; - @ManyToOne({ entity: () => {return Student} }) + @ManyToOne({ + entity: () => { + return Student; + }, + }) submitter!: Student; @Property({ type: 'datetime' }) submissionTime!: Date; - @ManyToOne({ entity: () => {return Group}, nullable: true }) + @ManyToOne({ + entity: () => { + return Group; + }, + nullable: true, + }) onBehalfOf?: Group; @Property({ type: 'json' }) diff --git a/backend/src/entities/classes/class-join-request.entity.ts b/backend/src/entities/classes/class-join-request.entity.ts index 86a30e3e..0ae38cd1 100644 --- a/backend/src/entities/classes/class-join-request.entity.ts +++ b/backend/src/entities/classes/class-join-request.entity.ts @@ -4,13 +4,25 @@ import { Class } from './class.entity.js'; @Entity() export class ClassJoinRequest { - @ManyToOne({ entity: () => {return Student}, primary: true }) + @ManyToOne({ + entity: () => { + return Student; + }, + primary: true, + }) requester!: Student; - @ManyToOne({ entity: () => {return Class}, primary: true }) + @ManyToOne({ + entity: () => { + return Class; + }, + primary: true, + }) class!: Class; - @Enum(() => {return ClassJoinRequestStatus}) + @Enum(() => { + return ClassJoinRequestStatus; + }) status!: ClassJoinRequestStatus; } diff --git a/backend/src/entities/classes/class.entity.ts b/backend/src/entities/classes/class.entity.ts index 2ad98c84..ecc11748 100644 --- a/backend/src/entities/classes/class.entity.ts +++ b/backend/src/entities/classes/class.entity.ts @@ -17,9 +17,13 @@ export class Class { @Property({ type: 'string' }) displayName!: string; - @ManyToMany(() => {return Teacher}) + @ManyToMany(() => { + return Teacher; + }) teachers!: Collection; - @ManyToMany(() => {return Student}) + @ManyToMany(() => { + return Student; + }) students!: Collection; } diff --git a/backend/src/entities/classes/teacher-invitation.entity.ts b/backend/src/entities/classes/teacher-invitation.entity.ts index feba8fc3..98d2bdd4 100644 --- a/backend/src/entities/classes/teacher-invitation.entity.ts +++ b/backend/src/entities/classes/teacher-invitation.entity.ts @@ -7,12 +7,27 @@ import { Class } from './class.entity.js'; */ @Entity() export class TeacherInvitation { - @ManyToOne({ entity: () => {return Teacher}, primary: true }) + @ManyToOne({ + entity: () => { + return Teacher; + }, + primary: true, + }) sender!: Teacher; - @ManyToOne({ entity: () => {return Teacher}, primary: true }) + @ManyToOne({ + entity: () => { + return Teacher; + }, + primary: true, + }) receiver!: Teacher; - @ManyToOne({ entity: () => {return Class}, primary: true }) + @ManyToOne({ + entity: () => { + return Class; + }, + primary: true, + }) class!: Class; } diff --git a/backend/src/entities/content/attachment.entity.ts b/backend/src/entities/content/attachment.entity.ts index 2ead7262..7a9dd946 100644 --- a/backend/src/entities/content/attachment.entity.ts +++ b/backend/src/entities/content/attachment.entity.ts @@ -3,7 +3,12 @@ import { LearningObject } from './learning-object.entity.js'; @Entity() export class Attachment { - @ManyToOne({ entity: () => {return LearningObject}, primary: true }) + @ManyToOne({ + entity: () => { + return LearningObject; + }, + primary: true, + }) learningObject!: LearningObject; @PrimaryKey({ type: 'integer' }) diff --git a/backend/src/entities/content/learning-object.entity.ts b/backend/src/entities/content/learning-object.entity.ts index c5bfe08f..bf499e8a 100644 --- a/backend/src/entities/content/learning-object.entity.ts +++ b/backend/src/entities/content/learning-object.entity.ts @@ -17,13 +17,22 @@ export class LearningObject { @PrimaryKey({ type: 'string' }) hruid!: string; - @Enum({ items: () => {return Language}, primary: true }) + @Enum({ + items: () => { + return Language; + }, + primary: true, + }) language!: Language; @PrimaryKey({ type: 'string' }) version: string = '1'; - @ManyToMany({ entity: () => {return Teacher} }) + @ManyToMany({ + entity: () => { + return Teacher; + }, + }) admins!: Teacher[]; @Property({ type: 'string' }) @@ -47,7 +56,12 @@ export class LearningObject { @Property({ type: 'array' }) skosConcepts!: string[]; - @Embedded({ entity: () => {return EducationalGoal}, array: true }) + @Embedded({ + entity: () => { + return EducationalGoal; + }, + array: true, + }) educationalGoals: EducationalGoal[] = []; @Property({ type: 'string' }) @@ -62,7 +76,11 @@ export class LearningObject { @Property({ type: 'integer' }) estimatedTime!: number; - @Embedded({ entity: () => {return ReturnValue} }) + @Embedded({ + entity: () => { + return ReturnValue; + }, + }) returnValue!: ReturnValue; @Property({ type: 'bool' }) @@ -71,7 +89,12 @@ export class LearningObject { @Property({ type: 'string', nullable: true }) contentLocation?: string; - @OneToMany({ entity: () => {return Attachment}, mappedBy: 'learningObject' }) + @OneToMany({ + entity: () => { + return Attachment; + }, + mappedBy: 'learningObject', + }) attachments: Attachment[] = []; @Property({ type: 'blob' }) diff --git a/backend/src/entities/content/learning-path.entity.ts b/backend/src/entities/content/learning-path.entity.ts index f758dace..28d3cadd 100644 --- a/backend/src/entities/content/learning-path.entity.ts +++ b/backend/src/entities/content/learning-path.entity.ts @@ -16,10 +16,19 @@ export class LearningPath { @PrimaryKey({ type: 'string' }) hruid!: string; - @Enum({ items: () => {return Language}, primary: true }) + @Enum({ + items: () => { + return Language; + }, + primary: true, + }) language!: Language; - @ManyToMany({ entity: () => {return Teacher} }) + @ManyToMany({ + entity: () => { + return Teacher; + }, + }) admins!: Teacher[]; @Property({ type: 'string' }) @@ -31,7 +40,12 @@ export class LearningPath { @Property({ type: 'blob' }) image!: string; - @Embedded({ entity: () => {return LearningPathNode}, array: true }) + @Embedded({ + entity: () => { + return LearningPathNode; + }, + array: true, + }) nodes: LearningPathNode[] = []; } @@ -40,7 +54,11 @@ export class LearningPathNode { @Property({ type: 'string' }) learningObjectHruid!: string; - @Enum({ items: () => {return Language} }) + @Enum({ + items: () => { + return Language; + }, + }) language!: Language; @Property({ type: 'string' }) @@ -52,7 +70,12 @@ export class LearningPathNode { @Property({ type: 'bool' }) startNode!: boolean; - @Embedded({ entity: () => {return LearningPathTransition}, array: true }) + @Embedded({ + entity: () => { + return LearningPathTransition; + }, + array: true, + }) transitions!: LearningPathTransition[]; } @@ -61,6 +84,10 @@ export class LearningPathTransition { @Property({ type: 'string' }) condition!: string; - @OneToOne({ entity: () => {return LearningPathNode} }) + @OneToOne({ + entity: () => { + return LearningPathNode; + }, + }) next!: LearningPathNode; } diff --git a/backend/src/entities/questions/answer.entity.ts b/backend/src/entities/questions/answer.entity.ts index 2690d50d..34558612 100644 --- a/backend/src/entities/questions/answer.entity.ts +++ b/backend/src/entities/questions/answer.entity.ts @@ -4,10 +4,20 @@ import { Teacher } from '../users/teacher.entity'; @Entity() export class Answer { - @ManyToOne({ entity: () => {return Teacher}, primary: true }) + @ManyToOne({ + entity: () => { + return Teacher; + }, + primary: true, + }) author!: Teacher; - @ManyToOne({ entity: () => {return Question}, primary: true }) + @ManyToOne({ + entity: () => { + return Question; + }, + primary: true, + }) toQuestion!: Question; @PrimaryKey({ type: 'integer' }) diff --git a/backend/src/entities/questions/question.entity.ts b/backend/src/entities/questions/question.entity.ts index 5830c816..444d2179 100644 --- a/backend/src/entities/questions/question.entity.ts +++ b/backend/src/entities/questions/question.entity.ts @@ -7,7 +7,12 @@ export class Question { @PrimaryKey({ type: 'string' }) learningObjectHruid!: string; - @Enum({ items: () => {return Language}, primary: true }) + @Enum({ + items: () => { + return Language; + }, + primary: true, + }) learningObjectLanguage!: Language; @PrimaryKey({ type: 'string' }) @@ -16,7 +21,11 @@ export class Question { @PrimaryKey({ type: 'integer' }) sequenceNumber!: number; - @ManyToOne({ entity: () => {return Student} }) + @ManyToOne({ + entity: () => { + return Student; + }, + }) author!: Student; @Property({ type: 'datetime' }) diff --git a/backend/src/entities/users/student.entity.ts b/backend/src/entities/users/student.entity.ts index ccfa7dfc..c5632e84 100644 --- a/backend/src/entities/users/student.entity.ts +++ b/backend/src/entities/users/student.entity.ts @@ -4,12 +4,20 @@ import { Class } from '../classes/class.entity.js'; import { Group } from '../assignments/group.entity.js'; import { StudentRepository } from '../../data/users/student-repository.js'; -@Entity({ repository: () => {return StudentRepository} }) +@Entity({ + repository: () => { + return StudentRepository; + }, +}) export class Student extends User { - @ManyToMany(() => {return Class}) + @ManyToMany(() => { + return Class; + }) classes!: Collection; - @ManyToMany(() => {return Group}) + @ManyToMany(() => { + return Group; + }) groups!: Collection; constructor( diff --git a/backend/src/entities/users/teacher.entity.ts b/backend/src/entities/users/teacher.entity.ts index eaaa8327..9f11a3b0 100644 --- a/backend/src/entities/users/teacher.entity.ts +++ b/backend/src/entities/users/teacher.entity.ts @@ -4,6 +4,8 @@ import { Class } from '../classes/class.entity.js'; @Entity() export class Teacher extends User { - @ManyToMany(() => {return Class}) + @ManyToMany(() => { + return Class; + }) classes!: Collection; } diff --git a/backend/src/routes/assignment.ts b/backend/src/routes/assignment.ts index eb49144f..4ae5756d 100644 --- a/backend/src/routes/assignment.ts +++ b/backend/src/routes/assignment.ts @@ -1,13 +1,10 @@ -import express from 'express' +import express from 'express'; const router = express.Router(); // Root endpoint used to search objects router.get('/', (req, res) => { res.json({ - assignments: [ - '0', - '1', - ] + assignments: ['0', '1'], }); }); @@ -17,7 +14,7 @@ router.get('/:id', (req, res) => { id: req.params.id, title: 'Dit is een test assignment', description: 'Een korte beschrijving', - groups: [ '0' ], + groups: ['0'], learningPath: '0', class: '0', links: { @@ -25,30 +22,24 @@ router.get('/:id', (req, res) => { submissions: `${req.baseUrl}/${req.params.id}`, }, }); -}) +}); router.get('/:id/submissions', (req, res) => { res.json({ - submissions: [ - '0' - ], + submissions: ['0'], }); }); router.get('/:id/groups', (req, res) => { res.json({ - groups: [ - '0' - ], + groups: ['0'], }); }); router.get('/:id/questions', (req, res) => { res.json({ - questions: [ - '0' - ], + questions: ['0'], }); }); -export default router \ No newline at end of file +export default router; diff --git a/backend/src/routes/class.ts b/backend/src/routes/class.ts index fa7a2310..6f8f324e 100644 --- a/backend/src/routes/class.ts +++ b/backend/src/routes/class.ts @@ -1,13 +1,10 @@ -import express from 'express' +import express from 'express'; const router = express.Router(); // Root endpoint used to search objects router.get('/', (req, res) => { res.json({ - classes: [ - '0', - '1', - ] + classes: ['0', '1'], }); }); @@ -16,40 +13,34 @@ router.get('/:id', (req, res) => { res.json({ id: req.params.id, displayName: 'Klas 4B', - teachers: [ '0' ], - students: [ '0' ], - joinRequests: [ '0' ], + teachers: ['0'], + students: ['0'], + joinRequests: ['0'], links: { self: `${req.baseUrl}/${req.params.id}`, classes: `${req.baseUrl}/${req.params.id}/invitations`, questions: `${req.baseUrl}/${req.params.id}/assignments`, students: `${req.baseUrl}/${req.params.id}/students`, - } + }, }); -}) +}); router.get('/:id/invitations', (req, res) => { res.json({ - invitations: [ - '0' - ], + invitations: ['0'], }); -}) +}); router.get('/:id/assignments', (req, res) => { res.json({ - assignments: [ - '0' - ], + assignments: ['0'], }); -}) +}); router.get('/:id/students', (req, res) => { res.json({ - students: [ - '0' - ], + students: ['0'], }); -}) +}); -export default router \ No newline at end of file +export default router; diff --git a/backend/src/routes/group.ts b/backend/src/routes/group.ts index e951a8a7..303f5215 100644 --- a/backend/src/routes/group.ts +++ b/backend/src/routes/group.ts @@ -1,13 +1,10 @@ -import express from 'express' +import express from 'express'; const router = express.Router(); // Root endpoint used to search objects router.get('/', (req, res) => { res.json({ - groups: [ - '0', - '1', - ] + groups: ['0', '1'], }); }); @@ -16,19 +13,19 @@ router.get('/:id', (req, res) => { res.json({ id: req.params.id, assignment: '0', - students: [ '0' ], - submissions: [ '0' ], + students: ['0'], + submissions: ['0'], // Reference to other endpoint // Should be less hardcoded - questions: `/group/${req.params.id}/question`, + questions: `/group/${req.params.id}/question`, }); -}) +}); // The list of questions a group has made router.get('/:id/question', (req, res) => { res.json({ - questions: [ '0' ], + questions: ['0'], }); -}) +}); -export default router \ No newline at end of file +export default router; diff --git a/backend/src/routes/login.ts b/backend/src/routes/login.ts index bc2ed3d8..33d5e6c3 100644 --- a/backend/src/routes/login.ts +++ b/backend/src/routes/login.ts @@ -1,4 +1,4 @@ -import express from 'express' +import express from 'express'; const router = express.Router(); // Returns login paths for IDP @@ -9,6 +9,6 @@ router.get('/', (req, res) => { leerkracht: '/login-leerkracht', leerling: '/login-leerling', }); -}) +}); -export default router \ No newline at end of file +export default router; diff --git a/backend/src/routes/question.ts b/backend/src/routes/question.ts index 040f742d..f683d998 100644 --- a/backend/src/routes/question.ts +++ b/backend/src/routes/question.ts @@ -1,13 +1,10 @@ -import express from 'express' +import express from 'express'; const router = express.Router(); // Root endpoint used to search objects router.get('/', (req, res) => { res.json({ - questions: [ - '0', - '1', - ] + questions: ['0', '1'], }); }); @@ -18,21 +15,20 @@ router.get('/:id', (req, res) => { student: '0', group: '0', time: new Date(2025, 1, 1), - content: 'Zijn alle gehele getallen groter dan 2 gelijk aan de som van 2 priemgetallen????', + content: + 'Zijn alle gehele getallen groter dan 2 gelijk aan de som van 2 priemgetallen????', learningObject: '0', links: { self: `${req.baseUrl}/${req.params.id}`, answers: `${req.baseUrl}/${req.params.id}/answers`, - } + }, }); -}) +}); router.get('/:id/answers', (req, res) => { res.json({ - answers: [ - '0' - ], - }) -}) + answers: ['0'], + }); +}); -export default router \ No newline at end of file +export default router; diff --git a/backend/src/routes/student.ts b/backend/src/routes/student.ts index bc3f588b..9cb0cdee 100644 --- a/backend/src/routes/student.ts +++ b/backend/src/routes/student.ts @@ -1,13 +1,10 @@ -import express from 'express' +import express from 'express'; const router = express.Router(); // Root endpoint used to search objects router.get('/', (req, res) => { res.json({ - students: [ - '0', - '1', - ] + students: ['0', '1'], }); }); @@ -30,30 +27,29 @@ router.get('/:id', (req, res) => { // The list of classes a student is in router.get('/:id/classes', (req, res) => { res.json({ - classes: [ '0' ], + classes: ['0'], }); -}) +}); // The list of submissions a student has made router.get('/:id/submissions', (req, res) => { res.json({ - submissions: [ '0' ], + submissions: ['0'], }); -}) +}); - // The list of assignments a student has router.get('/:id/assignments', (req, res) => { res.json({ - assignments: [ '0' ], + assignments: ['0'], }); -}) - +}); + // The list of groups a student is in router.get('/:id/groups', (req, res) => { res.json({ - groups: [ '0' ], + groups: ['0'], }); -}) +}); -export default router \ No newline at end of file +export default router; diff --git a/backend/src/routes/submission.ts b/backend/src/routes/submission.ts index 98acc842..cb4d3e85 100644 --- a/backend/src/routes/submission.ts +++ b/backend/src/routes/submission.ts @@ -1,13 +1,10 @@ -import express from 'express' +import express from 'express'; const router = express.Router(); // Root endpoint used to search objects router.get('/', (req, res) => { res.json({ - submissions: [ - '0', - '1', - ] + submissions: ['0', '1'], }); }); @@ -21,6 +18,6 @@ router.get('/:id', (req, res) => { content: 'Wortel 2 is rationeel', learningObject: '0', }); -}) +}); -export default router \ No newline at end of file +export default router; diff --git a/backend/src/routes/teacher.ts b/backend/src/routes/teacher.ts index f9de3aa5..a7c60bc9 100644 --- a/backend/src/routes/teacher.ts +++ b/backend/src/routes/teacher.ts @@ -1,13 +1,10 @@ -import express from 'express' +import express from 'express'; const router = express.Router(); // Root endpoint used to search objects router.get('/', (req, res) => { res.json({ - teachers: [ - '0', - '1', - ] + teachers: ['0', '1'], }); }); @@ -25,34 +22,27 @@ router.get('/:id', (req, res) => { invitations: `${req.baseUrl}/${req.params.id}/invitations`, }, }); -}) +}); // The questions students asked a teacher router.get('/:id/questions', (req, res) => { res.json({ - questions: [ - '0' - ], + questions: ['0'], }); }); // Invitations to other classes a teacher received router.get('/:id/invitations', (req, res) => { res.json({ - invitations: [ - '0' - ], + invitations: ['0'], }); }); // A list with ids of classes a teacher is in router.get('/:id/classes', (req, res) => { res.json({ - classes: [ - '0' - ], + classes: ['0'], }); }); - -export default router \ No newline at end of file +export default router; diff --git a/backend/src/services/learningPaths.ts b/backend/src/services/learningPaths.ts index 58703215..6baf74c7 100644 --- a/backend/src/services/learningPaths.ts +++ b/backend/src/services/learningPaths.ts @@ -1,6 +1,9 @@ import { fetchWithLogging } from '../util/apiHelper.js'; import { DWENGO_API_BASE } from '../config.js'; -import { LearningPath, LearningPathResponse } from '../interfaces/learningPath.js'; +import { + LearningPath, + LearningPathResponse, +} from '../interfaces/learningPath.js'; import { getLogger, Logger } from '../logging/initalize.js'; const logger: Logger = getLogger(); From 74ecd3453887cf07f6dfa7f434a20a17d868b29d Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Sun, 2 Mar 2025 15:25:27 +0100 Subject: [PATCH 035/180] fix: .js toevoegen aan imports --- backend/src/controllers/learningObjects.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/controllers/learningObjects.ts b/backend/src/controllers/learningObjects.ts index 90cd3f13..6fde1208 100644 --- a/backend/src/controllers/learningObjects.ts +++ b/backend/src/controllers/learningObjects.ts @@ -5,8 +5,8 @@ import { getLearningObjectsFromPath, } from '../services/learningObjects.js'; import { FALLBACK_LANG } from '../config.js'; -import { FilteredLearningObject } from '../interfaces/learningPath'; -import { getLogger } from '../logging/initalize'; +import { FilteredLearningObject } from '../interfaces/learningPath.js'; +import { getLogger } from '../logging/initalize.js'; export async function getAllLearningObjects( req: Request, From a28ec22f29fdb3127a7384b34b2ec8c1f253c5c9 Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Sun, 2 Mar 2025 16:33:50 +0100 Subject: [PATCH 036/180] feat(frontend): Added functionality to the frontend to log in. --- backend/.env.development.example | 5 + backend/package.json | 4 +- backend/src/app.ts | 8 +- backend/src/controllers/auth.ts | 33 ++++++ backend/src/middleware/auth/auth.ts | 1 - backend/src/middleware/cors.ts | 6 + backend/src/routes/auth.ts | 10 ++ backend/src/routes/login.ts | 14 --- backend/src/util/envvars.ts | 5 +- frontend/package.json | 4 +- frontend/src/App.vue | 2 + frontend/src/config.ts | 14 +++ frontend/src/router/index.ts | 5 + frontend/src/services/api-client.ts | 10 ++ frontend/src/services/auth-service.ts | 106 ++++++++++++++++++ frontend/src/store/auth-store.ts | 40 +++++++ frontend/src/views/HomePage.vue | 9 +- frontend/src/views/LoginPage.vue | 27 ++++- .../src/views/discussions/CallbackPage.vue | 24 ++++ package-lock.json | 101 +++++++++++++++-- 20 files changed, 395 insertions(+), 33 deletions(-) create mode 100644 backend/src/controllers/auth.ts create mode 100644 backend/src/middleware/cors.ts create mode 100644 backend/src/routes/auth.ts delete mode 100644 backend/src/routes/login.ts create mode 100644 frontend/src/config.ts create mode 100644 frontend/src/services/api-client.ts create mode 100644 frontend/src/services/auth-service.ts create mode 100644 frontend/src/store/auth-store.ts create mode 100644 frontend/src/views/discussions/CallbackPage.vue diff --git a/backend/.env.development.example b/backend/.env.development.example index 0b96f873..f809129d 100644 --- a/backend/.env.development.example +++ b/backend/.env.development.example @@ -6,6 +6,11 @@ DWENGO_DB_PASSWORD=postgres DWENGO_DB_UPDATE=true DWENGO_AUTH_STUDENT_URL=http://localhost:7080/realms/student +DWENGO_AUTH_STUDENT_CLIENT_ID=dwengo DWENGO_AUTH_STUDENT_JWKS_ENDPOINT=http://localhost:7080/realms/student/protocol/openid-connect/certs DWENGO_AUTH_TEACHER_URL=http://localhost:7080/realms/teacher +DWENGO_AUTH_TEACHER_CLIENT_ID=dwengo DWENGO_AUTH_TEACHER_JWKS_ENDPOINT=http://localhost:7080/realms/teacher/protocol/openid-connect/certs + +# Allow frontend from anywhere to access the backend (for testing purposes). Don't forget to remove this in production! +DWENGO_CORS_ALLOWED_ORIGINS=* diff --git a/backend/package.json b/backend/package.json index af8090f2..254158f1 100644 --- a/backend/package.json +++ b/backend/package.json @@ -24,7 +24,9 @@ "jwks-rsa": "^3.1.0", "uuid": "^11.1.0", "js-yaml": "^4.1.0", - "@types/js-yaml": "^4.0.9" + "@types/js-yaml": "^4.0.9", + "cors": "^2.8.5", + "@types/cors": "^2.8.17" }, "devDependencies": { "@mikro-orm/cli": "^6.4.6", diff --git a/backend/src/app.ts b/backend/src/app.ts index 521c40c5..250a6ebe 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -10,13 +10,13 @@ import assignmentRouter from './routes/assignment.js'; import submissionRouter from './routes/submission.js'; import classRouter from './routes/class.js'; import questionRouter from './routes/question.js'; -import loginRouter from './routes/login.js'; +import authRouter from './routes/auth.js'; import {authenticateUser} from "./middleware/auth/auth"; +import cors from "./middleware/cors"; const app: Express = express(); const port: string | number = getNumericEnvVar(EnvVars.Port); - // TODO Replace with Express routes app.get('/', (_, res: Response) => { res.json({ @@ -25,6 +25,7 @@ app.get('/', (_, res: Response) => { }); app.use(authenticateUser); +app.use(cors); app.use('/student', studentRouter); app.use('/group', groupRouter); @@ -32,8 +33,7 @@ app.use('/assignment', assignmentRouter); app.use('/submission', submissionRouter); app.use('/class', classRouter); app.use('/question', questionRouter); -app.use('/login', loginRouter); - +app.use('/auth', authRouter); app.use('/theme', themeRoutes); async function startServer() { diff --git a/backend/src/controllers/auth.ts b/backend/src/controllers/auth.ts new file mode 100644 index 00000000..800c3b99 --- /dev/null +++ b/backend/src/controllers/auth.ts @@ -0,0 +1,33 @@ +import {EnvVars, getEnvVar} from "../util/envvars"; + +type FrontendAuthConfig = { + student: FrontendIdpConfig, + teacher: FrontendIdpConfig +} + +type FrontendIdpConfig = { + authority: string, + clientId: string, + scope: string, + responseType: string +} + +const SCOPE = "openid profile email"; +const RESPONSE_TYPE = "code"; + +export function getFrontendAuthConfig(): FrontendAuthConfig { + return { + student: { + authority: getEnvVar(EnvVars.IdpStudentUrl), + clientId: getEnvVar(EnvVars.IdpStudentClientId), + scope: SCOPE, + responseType: RESPONSE_TYPE + }, + teacher: { + authority: getEnvVar(EnvVars.IdpTeacherUrl), + clientId: getEnvVar(EnvVars.IdpTeacherClientId), + scope: SCOPE, + responseType: RESPONSE_TYPE + }, + }; +} diff --git a/backend/src/middleware/auth/auth.ts b/backend/src/middleware/auth/auth.ts index 0bf63e3d..d06e6df2 100644 --- a/backend/src/middleware/auth/auth.ts +++ b/backend/src/middleware/auth/auth.ts @@ -58,7 +58,6 @@ const verifyJwtToken = expressjwt({ * Get an object with information about the authenticated user from a given authenticated request. */ function getAuthenticationInfo(req: AuthenticatedRequest): AuthenticationInfo | undefined { - console.log("hi"); if (!req.jwtPayload) { return; } diff --git a/backend/src/middleware/cors.ts b/backend/src/middleware/cors.ts new file mode 100644 index 00000000..e246aadf --- /dev/null +++ b/backend/src/middleware/cors.ts @@ -0,0 +1,6 @@ +import cors from "cors"; +import {EnvVars, getEnvVar} from "../util/envvars"; + +export default cors({ + origin: getEnvVar(EnvVars.CorsAllowedOrigins).split(',') +}); diff --git a/backend/src/routes/auth.ts b/backend/src/routes/auth.ts new file mode 100644 index 00000000..87c4183c --- /dev/null +++ b/backend/src/routes/auth.ts @@ -0,0 +1,10 @@ +import express from 'express' +import {getFrontendAuthConfig} from "../controllers/auth"; +const router = express.Router(); + +// returns auth configuration for frontend +router.get('/config', (req, res) => { + res.json(getFrontendAuthConfig()); +}); + +export default router; diff --git a/backend/src/routes/login.ts b/backend/src/routes/login.ts deleted file mode 100644 index 550e6d93..00000000 --- a/backend/src/routes/login.ts +++ /dev/null @@ -1,14 +0,0 @@ -import express from 'express' -const router = express.Router(); - -// returns login paths for IDP -router.get('/', (req, res) => { - res.json({ - // dummy variables, needs to be changed - // with IDP endpoints - leerkracht: '/login-leerkracht', - leerling: '/login-leerling', - }); -}) - -export default router \ No newline at end of file diff --git a/backend/src/util/envvars.ts b/backend/src/util/envvars.ts index 2dfcf640..60aa8025 100644 --- a/backend/src/util/envvars.ts +++ b/backend/src/util/envvars.ts @@ -15,10 +15,13 @@ export const EnvVars: { [key: string]: EnvVar } = { DbPassword: { key: DB_PREFIX + 'PASSWORD', required: true }, DbUpdate: { key: DB_PREFIX + 'UPDATE', defaultValue: false }, IdpStudentUrl: { key: STUDENT_IDP_PREFIX + 'URL', required: true }, + IdpStudentClientId: { key: STUDENT_IDP_PREFIX + 'CLIENT_ID', required: true }, IdpStudentJwksEndpoint: { key: STUDENT_IDP_PREFIX + 'JWKS_ENDPOINT', required: true }, IdpTeacherUrl: { key: TEACHER_IDP_PREFIX + 'URL', required: true }, + IdpTeacherClientId: { key: TEACHER_IDP_PREFIX + 'CLIENT_ID', required: true }, IdpTeacherJwksEndpoint: { key: TEACHER_IDP_PREFIX + 'JWKS_ENDPOINT', required: true }, - IdpAudience: { key: IDP_PREFIX + 'AUDIENCE', defaultValue: 'account' } + IdpAudience: { key: IDP_PREFIX + 'AUDIENCE', defaultValue: 'account' }, + CorsAllowedOrigins: { key: PREFIX + 'CORS_ALLOWED_ORIGINS', defaultValue: ''} } as const; /** diff --git a/frontend/package.json b/frontend/package.json index 2c2c2612..8c6f81d3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -18,7 +18,9 @@ "dependencies": { "vue": "^3.5.13", "vue-router": "^4.5.0", - "vuetify": "^3.7.12" + "vuetify": "^3.7.12", + "oidc-client-ts": "^3.1.0", + "axios": "^1.8.1" }, "devDependencies": { "@playwright/test": "^1.50.1", diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 7db110de..c1eb520c 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,4 +1,6 @@ - + diff --git a/idp/README.md b/idp/README.md index 3f3fd4ff..f67d0462 100644 --- a/idp/README.md +++ b/idp/README.md @@ -1,7 +1,9 @@ # Testdata in de IDP + De IDP in `docker-compose.yml` is zo geconfigureerd dat hij automatisch bij het starten een testconfiguratie inlaadt. Deze houdt in: -* Een realm `student` die de IDP voor leerlingen representeert. - * Hierin de gebruiker met username `testleerling1`, wachtwoord `password`. -* Een realm `teacher` die de IDP voor leerkrachten representeert. - * Hierin de gebruiker met username `testleerkracht1`, wachtwoord `password`. -* De admin-account (in de realm `master`) heeft username `admin` en wachtwoord `admin`. + +- Een realm `student` die de IDP voor leerlingen representeert. + - Hierin de gebruiker met username `testleerling1`, wachtwoord `password`. +- Een realm `teacher` die de IDP voor leerkrachten representeert. + - Hierin de gebruiker met username `testleerkracht1`, wachtwoord `password`. +- De admin-account (in de realm `master`) heeft username `admin` en wachtwoord `admin`. diff --git a/idp/student-realm.json b/idp/student-realm.json index 7b6bc94b..697fda34 100644 --- a/idp/student-realm.json +++ b/idp/student-realm.json @@ -1,2062 +1,2347 @@ { - "id" : "08a7ab0a-d483-4103-a781-76013864bf50", - "realm" : "student", - "notBefore" : 0, - "defaultSignatureAlgorithm" : "RS256", - "revokeRefreshToken" : false, - "refreshTokenMaxReuse" : 0, - "accessTokenLifespan" : 300, - "accessTokenLifespanForImplicitFlow" : 900, - "ssoSessionIdleTimeout" : 1800, - "ssoSessionMaxLifespan" : 36000, - "ssoSessionIdleTimeoutRememberMe" : 0, - "ssoSessionMaxLifespanRememberMe" : 0, - "offlineSessionIdleTimeout" : 2592000, - "offlineSessionMaxLifespanEnabled" : false, - "offlineSessionMaxLifespan" : 5184000, - "clientSessionIdleTimeout" : 0, - "clientSessionMaxLifespan" : 0, - "clientOfflineSessionIdleTimeout" : 0, - "clientOfflineSessionMaxLifespan" : 0, - "accessCodeLifespan" : 60, - "accessCodeLifespanUserAction" : 300, - "accessCodeLifespanLogin" : 1800, - "actionTokenGeneratedByAdminLifespan" : 43200, - "actionTokenGeneratedByUserLifespan" : 300, - "oauth2DeviceCodeLifespan" : 600, - "oauth2DevicePollingInterval" : 5, - "enabled" : true, - "sslRequired" : "external", - "registrationAllowed" : false, - "registrationEmailAsUsername" : false, - "rememberMe" : false, - "verifyEmail" : false, - "loginWithEmailAllowed" : true, - "duplicateEmailsAllowed" : false, - "resetPasswordAllowed" : false, - "editUsernameAllowed" : false, - "bruteForceProtected" : false, - "permanentLockout" : false, - "maxTemporaryLockouts" : 0, - "bruteForceStrategy" : "MULTIPLE", - "maxFailureWaitSeconds" : 900, - "minimumQuickLoginWaitSeconds" : 60, - "waitIncrementSeconds" : 60, - "quickLoginCheckMilliSeconds" : 1000, - "maxDeltaTimeSeconds" : 43200, - "failureFactor" : 30, - "roles" : { - "realm" : [ { - "id" : "a0bb00f5-0b3a-4d57-a3fc-a3f93cbe3427", - "name" : "offline_access", - "description" : "${role_offline-access}", - "composite" : false, - "clientRole" : false, - "containerId" : "08a7ab0a-d483-4103-a781-76013864bf50", - "attributes" : { } - }, { - "id" : "b3bf9566-098c-4167-9cce-f64c720ca511", - "name" : "default-roles-student", - "description" : "${role_default-roles}", - "composite" : true, - "composites" : { - "realm" : [ "offline_access", "uma_authorization" ], - "client" : { - "account" : [ "manage-account", "view-profile" ] + "id": "08a7ab0a-d483-4103-a781-76013864bf50", + "realm": "student", + "notBefore": 0, + "defaultSignatureAlgorithm": "RS256", + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 300, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "ssoSessionIdleTimeoutRememberMe": 0, + "ssoSessionMaxLifespanRememberMe": 0, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": false, + "offlineSessionMaxLifespan": 5184000, + "clientSessionIdleTimeout": 0, + "clientSessionMaxLifespan": 0, + "clientOfflineSessionIdleTimeout": 0, + "clientOfflineSessionMaxLifespan": 0, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "accessCodeLifespanLogin": 1800, + "actionTokenGeneratedByAdminLifespan": 43200, + "actionTokenGeneratedByUserLifespan": 300, + "oauth2DeviceCodeLifespan": 600, + "oauth2DevicePollingInterval": 5, + "enabled": true, + "sslRequired": "external", + "registrationAllowed": false, + "registrationEmailAsUsername": false, + "rememberMe": false, + "verifyEmail": false, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": false, + "editUsernameAllowed": false, + "bruteForceProtected": false, + "permanentLockout": false, + "maxTemporaryLockouts": 0, + "bruteForceStrategy": "MULTIPLE", + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 30, + "roles": { + "realm": [ + { + "id": "a0bb00f5-0b3a-4d57-a3fc-a3f93cbe3427", + "name": "offline_access", + "description": "${role_offline-access}", + "composite": false, + "clientRole": false, + "containerId": "08a7ab0a-d483-4103-a781-76013864bf50", + "attributes": {} + }, + { + "id": "b3bf9566-098c-4167-9cce-f64c720ca511", + "name": "default-roles-student", + "description": "${role_default-roles}", + "composite": true, + "composites": { + "realm": ["offline_access", "uma_authorization"], + "client": { + "account": ["manage-account", "view-profile"] + } + }, + "clientRole": false, + "containerId": "08a7ab0a-d483-4103-a781-76013864bf50", + "attributes": {} + }, + { + "id": "6d044f54-8ff3-4223-9e8c-771882da7a3f", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "composite": false, + "clientRole": false, + "containerId": "08a7ab0a-d483-4103-a781-76013864bf50", + "attributes": {} + } + ], + "client": { + "realm-management": [ + { + "id": "f125e557-2427-4eeb-95c5-b3dadf35f9c7", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes": {} + }, + { + "id": "33c7285a-7308-4752-acad-1fe59bf1c81a", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes": {} + }, + { + "id": "31fb3621-62c7-43c8-af98-a4add3470fcc", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes": {} + }, + { + "id": "e077c3c3-d573-494f-9cf8-34eca6603fc6", + "name": "realm-admin", + "description": "${role_realm-admin}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "manage-authorization", + "query-clients", + "manage-identity-providers", + "create-client", + "view-users", + "view-authorization", + "query-users", + "manage-users", + "view-identity-providers", + "impersonation", + "manage-realm", + "view-events", + "view-clients", + "manage-events", + "manage-clients", + "view-realm", + "query-groups", + "query-realms" + ] + } + }, + "clientRole": true, + "containerId": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes": {} + }, + { + "id": "8bbe59b1-7693-4274-bdde-c08f94ec3187", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes": {} + }, + { + "id": "0533162d-7dac-4ebf-87a2-7f72dad79d53", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "realm-management": ["query-groups", "query-users"] + } + }, + "clientRole": true, + "containerId": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes": {} + }, + { + "id": "d4b32078-67b4-4aa8-8ddf-01a820e7b64a", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes": {} + }, + { + "id": "2a48ab18-b710-41e7-8b8c-67a5cd6af685", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes": {} + }, + { + "id": "d71d575f-3f21-4f4a-b9e0-2628352aac8d", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes": {} + }, + { + "id": "7d3cd659-4ddd-45cd-8186-210431a25bbd", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes": {} + }, + { + "id": "3dbd18ca-11dc-463d-bf8e-e7d80928a90d", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes": {} + }, + { + "id": "d4a6ef1e-bf84-4bd6-8763-1b0c9997c109", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes": {} + }, + { + "id": "f0eab8d7-0570-44d3-94d0-2a43906d9f09", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes": {} + }, + { + "id": "0a24b91f-ef4a-4f4b-a753-1286dd59df2b", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "realm-management": ["query-clients"] + } + }, + "clientRole": true, + "containerId": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes": {} + }, + { + "id": "b307485c-8840-4c39-ba81-fb840fa404d1", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes": {} + }, + { + "id": "3719a5ed-be30-4d2c-93f5-cc6e6c0e792e", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes": {} + }, + { + "id": "d4b13416-9f5e-42fb-bfdd-6489093922da", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes": {} + }, + { + "id": "15ac861b-5440-4fe8-9f7d-857d75ec481d", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes": {} + }, + { + "id": "f05a8e4d-90ea-41f6-887b-0b6b1ecb9cd9", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "attributes": {} + } + ], + "dwengo": [], + "security-admin-console": [], + "admin-cli": [], + "account-console": [], + "broker": [ + { + "id": "da1edd82-7479-4e9d-ad66-9a4cf739e828", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "befe3d72-8102-49a6-8268-bce6def58159", + "attributes": {} + } + ], + "account": [ + { + "id": "5a3da53d-235b-4d12-b8ec-1573b13ebafc", + "name": "view-consent", + "description": "${role_view-consent}", + "composite": false, + "clientRole": true, + "containerId": "b3a22454-d780-4093-8333-9be6f6cd5855", + "attributes": {} + }, + { + "id": "cbc0c1d4-487b-488c-8566-1d4537212de8", + "name": "manage-account-links", + "description": "${role_manage-account-links}", + "composite": false, + "clientRole": true, + "containerId": "b3a22454-d780-4093-8333-9be6f6cd5855", + "attributes": {} + }, + { + "id": "79b0ed8f-bf10-4b01-bb2c-e7a58d57c798", + "name": "delete-account", + "description": "${role_delete-account}", + "composite": false, + "clientRole": true, + "containerId": "b3a22454-d780-4093-8333-9be6f6cd5855", + "attributes": {} + }, + { + "id": "b6aa748e-0fb0-4fa6-a0d1-3ea37c870467", + "name": "manage-account", + "description": "${role_manage-account}", + "composite": true, + "composites": { + "client": { + "account": ["manage-account-links"] + } + }, + "clientRole": true, + "containerId": "b3a22454-d780-4093-8333-9be6f6cd5855", + "attributes": {} + }, + { + "id": "ddaea6cd-ede8-49f7-9746-3a3a02fdeca5", + "name": "view-profile", + "description": "${role_view-profile}", + "composite": false, + "clientRole": true, + "containerId": "b3a22454-d780-4093-8333-9be6f6cd5855", + "attributes": {} + }, + { + "id": "061b2038-b415-4a45-89ec-7141004c0151", + "name": "view-applications", + "description": "${role_view-applications}", + "composite": false, + "clientRole": true, + "containerId": "b3a22454-d780-4093-8333-9be6f6cd5855", + "attributes": {} + }, + { + "id": "95972aa1-6666-421c-8596-a91eee54b0e8", + "name": "view-groups", + "description": "${role_view-groups}", + "composite": false, + "clientRole": true, + "containerId": "b3a22454-d780-4093-8333-9be6f6cd5855", + "attributes": {} + }, + { + "id": "1cf27d94-d88d-42d3-b8f3-ede1f127ac45", + "name": "manage-consent", + "description": "${role_manage-consent}", + "composite": true, + "composites": { + "client": { + "account": ["view-consent"] + } + }, + "clientRole": true, + "containerId": "b3a22454-d780-4093-8333-9be6f6cd5855", + "attributes": {} + } + ] } - }, - "clientRole" : false, - "containerId" : "08a7ab0a-d483-4103-a781-76013864bf50", - "attributes" : { } - }, { - "id" : "6d044f54-8ff3-4223-9e8c-771882da7a3f", - "name" : "uma_authorization", - "description" : "${role_uma_authorization}", - "composite" : false, - "clientRole" : false, - "containerId" : "08a7ab0a-d483-4103-a781-76013864bf50", - "attributes" : { } - } ], - "client" : { - "realm-management" : [ { - "id" : "f125e557-2427-4eeb-95c5-b3dadf35f9c7", - "name" : "manage-authorization", - "description" : "${role_manage-authorization}", - "composite" : false, - "clientRole" : true, - "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "attributes" : { } - }, { - "id" : "33c7285a-7308-4752-acad-1fe59bf1c81a", - "name" : "manage-identity-providers", - "description" : "${role_manage-identity-providers}", - "composite" : false, - "clientRole" : true, - "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "attributes" : { } - }, { - "id" : "31fb3621-62c7-43c8-af98-a4add3470fcc", - "name" : "query-clients", - "description" : "${role_query-clients}", - "composite" : false, - "clientRole" : true, - "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "attributes" : { } - }, { - "id" : "e077c3c3-d573-494f-9cf8-34eca6603fc6", - "name" : "realm-admin", - "description" : "${role_realm-admin}", - "composite" : true, - "composites" : { - "client" : { - "realm-management" : [ "manage-authorization", "query-clients", "manage-identity-providers", "create-client", "view-users", "view-authorization", "query-users", "manage-users", "view-identity-providers", "impersonation", "manage-realm", "view-events", "view-clients", "manage-events", "manage-clients", "view-realm", "query-groups", "query-realms" ] - } + }, + "groups": [], + "defaultRole": { + "id": "b3bf9566-098c-4167-9cce-f64c720ca511", + "name": "default-roles-student", + "description": "${role_default-roles}", + "composite": true, + "clientRole": false, + "containerId": "08a7ab0a-d483-4103-a781-76013864bf50" + }, + "requiredCredentials": ["password"], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpPolicyCodeReusable": false, + "otpSupportedApplications": ["totpAppFreeOTPName", "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName"], + "localizationTexts": {}, + "webAuthnPolicyRpEntityName": "keycloak", + "webAuthnPolicySignatureAlgorithms": ["ES256", "RS256"], + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "webAuthnPolicyCreateTimeout": 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyAcceptableAaguids": [], + "webAuthnPolicyExtraOrigins": [], + "webAuthnPolicyPasswordlessRpEntityName": "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms": ["ES256", "RS256"], + "webAuthnPolicyPasswordlessRpId": "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", + "webAuthnPolicyPasswordlessCreateTimeout": 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyPasswordlessAcceptableAaguids": [], + "webAuthnPolicyPasswordlessExtraOrigins": [], + "users": [ + { + "id": "79e9a395-d7e4-48c9-a06e-702435bae290", + "username": "testleerling1", + "firstName": "Gerald", + "lastName": "Schmittinger", + "email": "Gerald.Schmittinger@UGent.be", + "emailVerified": false, + "createdTimestamp": 1740858528405, + "enabled": true, + "totp": false, + "credentials": [ + { + "id": "c31a708f-8614-4144-a25f-3e976c9035ce", + "type": "password", + "userLabel": "My password", + "createdDate": 1740858548515, + "secretData": "{\"value\":\"yDKIAbZPuVXBGk4zjiqE/YFcPDm1vjXLwTrPUrvMhXY=\",\"salt\":\"tYvjd4mhV2UWeOUssK01Cw==\",\"additionalParameters\":{}}", + "credentialData": "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}" + } + ], + "disableableCredentialTypes": [], + "requiredActions": [], + "realmRoles": ["default-roles-student"], + "notBefore": 0, + "groups": [] + } + ], + "scopeMappings": [ + { + "clientScope": "offline_access", + "roles": ["offline_access"] + } + ], + "clientScopeMappings": { + "account": [ + { + "client": "account-console", + "roles": ["manage-account", "view-groups"] + } + ] + }, + "clients": [ + { + "id": "b3a22454-d780-4093-8333-9be6f6cd5855", + "clientId": "account", + "name": "${client_account}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/student/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": ["/realms/student/account/*"], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, - "clientRole" : true, - "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "attributes" : { } - }, { - "id" : "8bbe59b1-7693-4274-bdde-c08f94ec3187", - "name" : "create-client", - "description" : "${role_create-client}", - "composite" : false, - "clientRole" : true, - "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "attributes" : { } - }, { - "id" : "0533162d-7dac-4ebf-87a2-7f72dad79d53", - "name" : "view-users", - "description" : "${role_view-users}", - "composite" : true, - "composites" : { - "client" : { - "realm-management" : [ "query-groups", "query-users" ] - } + { + "id": "854c221b-630c-4cc3-9365-bd254246dd69", + "clientId": "account-console", + "name": "${client_account-console}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/student/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": ["/realms/student/account/*"], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "f33b40fe-bb9e-4254-ada9-f98dd203641b", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, - "clientRole" : true, - "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "attributes" : { } - }, { - "id" : "d4b32078-67b4-4aa8-8ddf-01a820e7b64a", - "name" : "view-authorization", - "description" : "${role_view-authorization}", - "composite" : false, - "clientRole" : true, - "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "attributes" : { } - }, { - "id" : "2a48ab18-b710-41e7-8b8c-67a5cd6af685", - "name" : "query-users", - "description" : "${role_query-users}", - "composite" : false, - "clientRole" : true, - "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "attributes" : { } - }, { - "id" : "d71d575f-3f21-4f4a-b9e0-2628352aac8d", - "name" : "manage-users", - "description" : "${role_manage-users}", - "composite" : false, - "clientRole" : true, - "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "attributes" : { } - }, { - "id" : "7d3cd659-4ddd-45cd-8186-210431a25bbd", - "name" : "impersonation", - "description" : "${role_impersonation}", - "composite" : false, - "clientRole" : true, - "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "attributes" : { } - }, { - "id" : "3dbd18ca-11dc-463d-bf8e-e7d80928a90d", - "name" : "view-identity-providers", - "description" : "${role_view-identity-providers}", - "composite" : false, - "clientRole" : true, - "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "attributes" : { } - }, { - "id" : "d4a6ef1e-bf84-4bd6-8763-1b0c9997c109", - "name" : "manage-realm", - "description" : "${role_manage-realm}", - "composite" : false, - "clientRole" : true, - "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "attributes" : { } - }, { - "id" : "f0eab8d7-0570-44d3-94d0-2a43906d9f09", - "name" : "view-events", - "description" : "${role_view-events}", - "composite" : false, - "clientRole" : true, - "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "attributes" : { } - }, { - "id" : "0a24b91f-ef4a-4f4b-a753-1286dd59df2b", - "name" : "view-clients", - "description" : "${role_view-clients}", - "composite" : true, - "composites" : { - "client" : { - "realm-management" : [ "query-clients" ] - } + { + "id": "9449aa8b-d5cc-4b9f-bb01-be1e5a896f2f", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "client.use.lightweight.access.token.enabled": "true" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, - "clientRole" : true, - "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "attributes" : { } - }, { - "id" : "b307485c-8840-4c39-ba81-fb840fa404d1", - "name" : "manage-events", - "description" : "${role_manage-events}", - "composite" : false, - "clientRole" : true, - "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "attributes" : { } - }, { - "id" : "3719a5ed-be30-4d2c-93f5-cc6e6c0e792e", - "name" : "manage-clients", - "description" : "${role_manage-clients}", - "composite" : false, - "clientRole" : true, - "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "attributes" : { } - }, { - "id" : "d4b13416-9f5e-42fb-bfdd-6489093922da", - "name" : "view-realm", - "description" : "${role_view-realm}", - "composite" : false, - "clientRole" : true, - "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "attributes" : { } - }, { - "id" : "15ac861b-5440-4fe8-9f7d-857d75ec481d", - "name" : "query-groups", - "description" : "${role_query-groups}", - "composite" : false, - "clientRole" : true, - "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "attributes" : { } - }, { - "id" : "f05a8e4d-90ea-41f6-887b-0b6b1ecb9cd9", - "name" : "query-realms", - "description" : "${role_query-realms}", - "composite" : false, - "clientRole" : true, - "containerId" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "attributes" : { } - } ], - "dwengo" : [ ], - "security-admin-console" : [ ], - "admin-cli" : [ ], - "account-console" : [ ], - "broker" : [ { - "id" : "da1edd82-7479-4e9d-ad66-9a4cf739e828", - "name" : "read-token", - "description" : "${role_read-token}", - "composite" : false, - "clientRole" : true, - "containerId" : "befe3d72-8102-49a6-8268-bce6def58159", - "attributes" : { } - } ], - "account" : [ { - "id" : "5a3da53d-235b-4d12-b8ec-1573b13ebafc", - "name" : "view-consent", - "description" : "${role_view-consent}", - "composite" : false, - "clientRole" : true, - "containerId" : "b3a22454-d780-4093-8333-9be6f6cd5855", - "attributes" : { } - }, { - "id" : "cbc0c1d4-487b-488c-8566-1d4537212de8", - "name" : "manage-account-links", - "description" : "${role_manage-account-links}", - "composite" : false, - "clientRole" : true, - "containerId" : "b3a22454-d780-4093-8333-9be6f6cd5855", - "attributes" : { } - }, { - "id" : "79b0ed8f-bf10-4b01-bb2c-e7a58d57c798", - "name" : "delete-account", - "description" : "${role_delete-account}", - "composite" : false, - "clientRole" : true, - "containerId" : "b3a22454-d780-4093-8333-9be6f6cd5855", - "attributes" : { } - }, { - "id" : "b6aa748e-0fb0-4fa6-a0d1-3ea37c870467", - "name" : "manage-account", - "description" : "${role_manage-account}", - "composite" : true, - "composites" : { - "client" : { - "account" : [ "manage-account-links" ] - } + { + "id": "befe3d72-8102-49a6-8268-bce6def58159", + "clientId": "broker", + "name": "${client_broker}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "true" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, - "clientRole" : true, - "containerId" : "b3a22454-d780-4093-8333-9be6f6cd5855", - "attributes" : { } - }, { - "id" : "ddaea6cd-ede8-49f7-9746-3a3a02fdeca5", - "name" : "view-profile", - "description" : "${role_view-profile}", - "composite" : false, - "clientRole" : true, - "containerId" : "b3a22454-d780-4093-8333-9be6f6cd5855", - "attributes" : { } - }, { - "id" : "061b2038-b415-4a45-89ec-7141004c0151", - "name" : "view-applications", - "description" : "${role_view-applications}", - "composite" : false, - "clientRole" : true, - "containerId" : "b3a22454-d780-4093-8333-9be6f6cd5855", - "attributes" : { } - }, { - "id" : "95972aa1-6666-421c-8596-a91eee54b0e8", - "name" : "view-groups", - "description" : "${role_view-groups}", - "composite" : false, - "clientRole" : true, - "containerId" : "b3a22454-d780-4093-8333-9be6f6cd5855", - "attributes" : { } - }, { - "id" : "1cf27d94-d88d-42d3-b8f3-ede1f127ac45", - "name" : "manage-consent", - "description" : "${role_manage-consent}", - "composite" : true, - "composites" : { - "client" : { - "account" : [ "view-consent" ] - } + { + "id": "714243ae-72cc-4c26-842a-047357b5919a", + "clientId": "dwengo", + "name": "Dwengo", + "description": "", + "rootUrl": "http://localhost:5173", + "adminUrl": "http://localhost:5173", + "baseUrl": "/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-jwt", + "redirectUris": ["urn:ietf:wg:oauth:2.0:oob", "http://localhost:5173/*", "http://localhost:5173"], + "webOrigins": ["+"], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": true, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": true, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "oidc.ciba.grant.enabled": "false", + "client.secret.creation.time": "1740860818", + "backchannel.logout.session.required": "true", + "token.endpoint.auth.signing.alg": "RS256", + "post.logout.redirect.uris": "+", + "frontchannel.logout.session.required": "true", + "oauth2.device.authorization.grant.enabled": "false", + "display.on.consent.screen": "false", + "backchannel.logout.revoke.offline.tokens": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, - "clientRole" : true, - "containerId" : "b3a22454-d780-4093-8333-9be6f6cd5855", - "attributes" : { } - } ] + { + "id": "0b06aaa3-717d-4a52-ab46-295a6571b642", + "clientId": "realm-management", + "name": "${client_realm-management}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "true" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] + }, + { + "id": "dfc7248c-3794-4e3b-aed2-3ee553cd0feb", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "rootUrl": "${authAdminUrl}", + "baseUrl": "/admin/student/console/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": ["/admin/student/console/*"], + "webOrigins": ["+"], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "client.use.lightweight.access.token.enabled": "true", + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "9e9ff295-30c9-43f1-a11a-773724709c07", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] + } + ], + "clientScopes": [ + { + "id": "0721b27a-284f-4e6d-af70-b6f190ebdcd4", + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${emailScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "d256bdc1-8983-41e0-b8fa-fcf45653045e", + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + }, + { + "id": "651c2415-db30-40ed-bdef-745b6ea744ed", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "573f6eea-7626-44fe-9855-50f15c3939ba", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "consent.screen.text": "", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "3489c748-3cc7-4350-9351-2955fc7084ba", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "id": "00afe548-c677-4595-8478-16f752c2713a", + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + }, + { + "id": "1448ed2b-ec1d-4bf4-a8b7-00cb85459289", + "name": "address", + "description": "OpenID Connect built-in scope: address", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${addressScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "12d491b6-5d74-4168-ac5c-517ebc2f1de4", + "name": "address", + "protocol": "openid-connect", + "protocolMapper": "oidc-address-mapper", + "consentRequired": false, + "config": { + "user.attribute.formatted": "formatted", + "user.attribute.country": "country", + "introspection.token.claim": "true", + "user.attribute.postal_code": "postal_code", + "userinfo.token.claim": "true", + "user.attribute.street": "street", + "id.token.claim": "true", + "user.attribute.region": "region", + "access.token.claim": "true", + "user.attribute.locality": "locality" + } + } + ] + }, + { + "id": "52223fb1-9651-4cdf-8317-a1301d4042f7", + "name": "organization", + "description": "Additional claims about the organization a subject belongs to", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${organizationScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "dccc4214-ece6-4235-8119-ee8cb954c29a", + "name": "organization", + "protocol": "openid-connect", + "protocolMapper": "oidc-organization-membership-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "organization", + "jsonType.label": "String", + "multivalued": "true" + } + } + ] + }, + { + "id": "8be22542-e327-4a25-8265-a34a29607d1b", + "name": "service_account", + "description": "Specific scope for a client enabled for service accounts", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "cf89064a-0af3-4a4b-a838-3528a8f4d780", + "name": "Client IP Address", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientAddress", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientAddress", + "jsonType.label": "String" + } + }, + { + "id": "dc0f77e6-cc20-4c0a-baf3-f45046d749d1", + "name": "Client ID", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "client_id", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "client_id", + "jsonType.label": "String" + } + }, + { + "id": "d63fd29a-3613-4529-a8e4-3a7d7e9f5802", + "name": "Client Host", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientHost", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientHost", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "d9079603-62b7-4680-9d01-950daae75d6b", + "name": "saml_organization", + "description": "Organization Membership", + "protocol": "saml", + "attributes": { + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "d826fc58-b006-49ad-93dc-a76700e800df", + "name": "organization", + "protocol": "saml", + "protocolMapper": "saml-organization-membership-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "171d8267-87da-4a4b-9346-d901d470248b", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${phoneScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "f8bb18d4-af9d-49b0-a61f-cc81887870cd", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", + "jsonType.label": "String" + } + }, + { + "id": "88a2c658-9b61-40a2-abd5-69c501286031", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "phoneNumberVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "ea3b84ac-a91f-4a3d-be4e-893e11eaf4a1", + "name": "acr", + "description": "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "152d66d4-524f-47f1-a592-be3a0c043a4f", + "name": "acr loa level", + "protocol": "openid-connect", + "protocolMapper": "oidc-acr-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "id": "2fc1ad0d-1065-4196-8d1b-c61525c9425d", + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "9d537486-f6bf-4856-91fc-ca3acaa78814", + "name": "upn", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "upn", + "jsonType.label": "String" + } + }, + { + "id": "55425438-4111-47a0-9a36-fec9dbbc6a8a", + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "multivalued": "true", + "user.attribute": "foo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "0d186f4e-ef6d-4fbc-9593-081e0d5ad171", + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${profileScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "bb8bb550-2db6-4631-97dc-1d115d0e3034", + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "given_name", + "jsonType.label": "String" + } + }, + { + "id": "c942089b-2898-4052-a64d-85b61e27aaa4", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String" + } + }, + { + "id": "5ff3a9ca-7036-458c-b0dc-41216292d210", + "name": "updated at", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "updatedAt", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "updated_at", + "jsonType.label": "long" + } + }, + { + "id": "41f93d62-4074-4373-a270-9bdf1e298cb5", + "name": "website", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "website", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "website", + "jsonType.label": "String" + } + }, + { + "id": "ffec7d63-0f78-41ea-8023-6c7c64661b34", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + }, + { + "id": "4a514ae7-d29f-4979-8df9-a97b36a81a96", + "name": "profile", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "profile", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "profile", + "jsonType.label": "String" + } + }, + { + "id": "286e349b-cb9f-41b1-b9dc-d787f13e9d99", + "name": "nickname", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "nickname", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "nickname", + "jsonType.label": "String" + } + }, + { + "id": "f5177603-55b1-4abe-aee6-b1e5a05e37f6", + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "id": "a31114d7-05fc-40c1-9ea8-6977f6f0bec5", + "name": "zoneinfo", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "zoneinfo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "zoneinfo", + "jsonType.label": "String" + } + }, + { + "id": "8884be77-648d-4083-b0cf-57130162c8dc", + "name": "gender", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "gender", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "gender", + "jsonType.label": "String" + } + }, + { + "id": "61840434-c79f-455a-a914-117977197304", + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "family_name", + "jsonType.label": "String" + } + }, + { + "id": "1f40ff0b-1664-4259-846b-ab707c76d33b", + "name": "middle name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "middleName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "middle_name", + "jsonType.label": "String" + } + }, + { + "id": "8534d400-8a81-4ae3-b51f-78b93e5a2045", + "name": "picture", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "picture", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "picture", + "jsonType.label": "String" + } + }, + { + "id": "82a0e240-0824-41b9-b6e8-856a72d1e930", + "name": "birthdate", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "birthdate", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "birthdate", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "a5cedc85-d9e9-42e1-9ea3-ff37d21d5e27", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "19009128-590f-4bc9-80de-c9ba4aae822d", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "3b6bb88b-c833-4bb5-9bd0-95831aa2ad0d", + "name": "basic", + "description": "OpenID Connect scope for add all basic claims to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "ce925803-aec2-47cb-a3b9-4bef12c80367", + "name": "sub", + "protocol": "openid-connect", + "protocolMapper": "oidc-sub-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + }, + { + "id": "58729b3a-3816-460e-bf2e-d0d2206c1830", + "name": "auth_time", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "AUTH_TIME", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "auth_time", + "jsonType.label": "long" + } + } + ] + }, + { + "id": "7aa2d936-3edb-45e5-bae0-b4a618d06371", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "consent.screen.text": "${rolesScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "a9d1e8e2-ca10-4904-8a42-7708b0bfdefa", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "1f217073-ad43-483b-b0d5-f3ca4c74282f", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "61b0a069-8b67-4692-bcca-66a197b230eb", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + } + ], + "defaultDefaultClientScopes": ["role_list", "saml_organization", "profile", "email", "roles", "web-origins", "acr", "basic"], + "defaultOptionalClientScopes": ["offline_access", "address", "phone", "microprofile-jwt", "organization"], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "referrerPolicy": "no-referrer", + "xRobotsTag": "none", + "xFrameOptions": "SAMEORIGIN", + "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection": "1; mode=block", + "strictTransportSecurity": "max-age=31536000; includeSubDomains" + }, + "smtpServer": {}, + "eventsEnabled": false, + "eventsListeners": ["jboss-logging"], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "identityProviders": [], + "identityProviderMappers": [], + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "9eac5531-7f25-493f-a721-6c5e65cd34c2", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": ["200"] + } + }, + { + "id": "d9319a22-4c67-4b08-822f-4162a1ee01bc", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": ["true"] + } + }, + { + "id": "21456c8e-7f6b-4e49-a3e1-bea7f900e2fb", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "4872e99b-b55b-4e13-8a93-63e853289cac", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "a118a194-09f5-435d-9d4b-363813413167", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": ["true"], + "client-uris-must-match": ["true"] + } + }, + { + "id": "e32b1e26-6571-4b0c-a205-0fbb3de44384", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": ["true"] + } + }, + { + "id": "9dbe6752-9978-42a3-9210-9ec166140de2", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-usermodel-attribute-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-address-mapper", + "saml-role-list-mapper", + "saml-user-property-mapper", + "oidc-usermodel-property-mapper", + "oidc-full-name-mapper", + "saml-user-attribute-mapper" + ] + } + }, + { + "id": "7027b3f4-d877-4814-ac78-f1edb8eb89b0", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-role-list-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-address-mapper", + "saml-user-property-mapper", + "oidc-usermodel-attribute-mapper", + "saml-user-attribute-mapper", + "oidc-usermodel-property-mapper", + "oidc-full-name-mapper" + ] + } + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "819cfc66-a997-4747-9d90-a7f0c09774bf", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "kid": ["eb74df73-3f34-457d-95c7-5ad909107703"], + "secret": ["1K8IJiDODmotHJPStrXhtA"], + "priority": ["100"] + } + }, + { + "id": "299857cd-52a4-4981-8171-02e7d8f12960", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "privateKey": [ + "MIIEpAIBAAKCAQEA1MRmAT/yImkVfPMBxC0QHdC4DQfuWUTjKeEku+gMI9jX5ChUzzzVugcvZWmxBNcvOz7p6R8EdPllZKIwFSH5WvQ1w1VIgQwIlYfpi/pknfftLd66MI2fXrQK19dRTeQRivEf39GTfBQ2Xc7y1q7zbMo5TVxATJ3DgPi13dYO7zVPpGTiQQeYiezlcBedyGe4cS1g6oBoaVif1QPY1Ni2vEjJhczNMGI408tIFws8G04Tlno814nT0ysdflUSGcRUku41NtfM9hr57LQ459sGYho8Pn11lDuiUWkomJv0y3GJ1wFBvQbDvI+6QvEdFu0GxShrlcORrNmj3BwOOLhB7wIDAQABAoIBAA6zrXq7oO8YxMfYANC97mWpBPa9jA42EN5VdNTZIXGeq7hTwxx4zynmEjPXPEih190nqUEXCBdPHl74SAtFyDWtN0PSkkp8euFePViTSj2SIpzvTX1KY+9G0JL+iVsw/bdUlwe/swm5WdJcmPIVr7NeO9xpGfZRVm+EgAieoHSN4Z7g20wLbVz1fya+6O5Hy+IGezamIA4tchk+4hyiVpSh2TcdjkJJZWOlHKPkwWU/MYQbJibuea5jLoWA39NIqV2l5GT0SoCbffGJNb9CMTTGmXoK5zNwHhG+M0a4eP1vbFDLaoDne86JySmTdv/WrTFFa3veelw2K8PHDybuB70CgYEA/gbxqLZYkJcEpqsjM/XcISFJ09icJLKl5r2l/Dm4Qq587QniQYribX/PPLfDhgVwPByQe3rccq9FoiILycTdIwgSMTsg5fzvbLJTqMAcl2r0zJgHVIDc6iXnytuE0FffKN0kSKL1C4d6n6vKoCGvOcZoXK5jxgzpY8lasvKxhCsCgYEA1mtr7CDYY3qPmTu4/Uz6cFgX8RDMZZ11AQQXNMsKHIu5C4xLeYmJMlpt0y4h52/NWRzh2svdw3SEZTCfP1WVC7StfP8KD8QdwVkQlY5EGkiz9uRtEgwk8chkOTIm2JedeRL6YWlTgnH9PIuGq84OOnEbFjVN3Lbx3N1QuQfVA00CgYEAybA1uuBcXSCqfrIuVxkD2AIYHe1DvBdjhVpaKXKii78CTSmlzKg6svnhTrIQuZ4jyHZdeMzJrvzeaqZheaemdCP6XcA2lKRIbKMBrWAq00YGa1LhrwRJYlcKPJQiVVEPS+CY6FsJ+Edu4suBK7bS6ypOvhdv/FVQEPxT2PS8YNUCgYEAxwJ+8XNuw63ud9+Zi+gVjY4F8qWPwESLYz0DuOk2YlZAknpNVumTYBvUUSxBJYh8RFhtO+D53D5Z331oYKUzJ+EzII+qLAXvRBRBMz4O8YJHHkDXBugkphBDDV8B9QeLjeNSZnUWoDziOH6bqPwf8pgl9s/Ui6V1CHSVRpcBWwUCgYA2kMgu7qS5kLtUWySPzW4nTKwhN+HFTIbRrNrECxXmxroigTEyfBFuNR5QaeYYrAtqgY1m5Lev//2GnWM7dAr7hewj6qfGszrvegHsqMs4cakVqEOtbrWxL+WtWPaIdjJ+x7ZoMnZxZDg3ysemybNHHwSyBsp1TDc+glzmMtJtLA==" + ], + "keyUse": ["SIG"], + "certificate": [ + "MIICnTCCAYUCBgGVUbFIeTANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdzdHVkZW50MB4XDTI1MDMwMTEyMzAyN1oXDTM1MDMwMTEyMzIwN1owEjEQMA4GA1UEAwwHc3R1ZGVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANTEZgE/8iJpFXzzAcQtEB3QuA0H7llE4ynhJLvoDCPY1+QoVM881boHL2VpsQTXLzs+6ekfBHT5ZWSiMBUh+Vr0NcNVSIEMCJWH6Yv6ZJ337S3eujCNn160CtfXUU3kEYrxH9/Rk3wUNl3O8tau82zKOU1cQEydw4D4td3WDu81T6Rk4kEHmIns5XAXnchnuHEtYOqAaGlYn9UD2NTYtrxIyYXMzTBiONPLSBcLPBtOE5Z6PNeJ09MrHX5VEhnEVJLuNTbXzPYa+ey0OOfbBmIaPD59dZQ7olFpKJib9MtxidcBQb0Gw7yPukLxHRbtBsUoa5XDkazZo9wcDji4Qe8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAedqvKOBsz4IKKzkWHIQnN5H8dQKnuPUMdWewOwmMGIUdBU9k6aS+y+BB7mugF/Hnr8Lw5d2AHwVLj2VyP4Pq0d2My3Ihxi0vr6sSfxVHuD9y/a7FxDGVTkCvmy5DOmpF/kdNnL9xG5ZivHaucnrIHHGMcQCdbWAaac0qPZihv9pdMZFMtI3aiBO5jVJ7KP8iLNKsshg60mxCOPzauMVXi+rqqqhGAgMKAL4hjjvdIKTLWwmthnmAlGqlTk/7H82hS9aKygufXszXWdFAYhX/r8/hjyc+6zJUvkG20uRWnkR35gya7jQoZ2O6OvkQf0mgSvzgIP3xoYV2uKYD03wINg==" + ], + "priority": ["100"] + } + }, + { + "id": "3d6bfeeb-fa86-435e-8c39-6f547a0f4a38", + "name": "hmac-generated-hs512", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "kid": ["176e970f-5915-4d27-8233-8fab6d7ad947"], + "secret": [ + "sXeOdtyIPpH_kcZWikHFjTur9yWok0QUwKi95l8wHp6kTVX9vhoZL2siNHRoFnn8tFgT4JZbR0bMsD57qAXlmVjA830Ny_GZdhL_PFWQh7JYMEJrl-1nyLy_SReQXRtq_q9tKUafUZqeYSKBlUYZ7D4jNRJ4-uniq80Ger-4ee0" + ], + "priority": ["100"], + "algorithm": ["HS512"] + } + }, + { + "id": "df1247b5-041e-4ae8-b7fc-26c4b6f5ff67", + "name": "rsa-enc-generated", + "providerId": "rsa-enc-generated", + "subComponents": {}, + "config": { + "privateKey": [ + "MIIEpAIBAAKCAQEAq0piY/PaZh1IX46e0G6tCPtfRx7Q8zGslOFSBLR9PNAdSlBpYiV9kOpN1kTK2Sca5j4yyO9HAFK5j+zh/cy8SsP1iyuI0sCPG7NMKV1pP5Y753wTC0lTq8z16bvXPvPYrPRKgGDmU7Ww0/WD6/P+z9Li/+ujFHzzzfoPuQvbBhma6A4oadsC+zun/mWCyiD14mB+X00BeAIsxKJZ/Sd+U4lMkkvmpoXyx61xK+j48EAZ18u7FprlvUjgGzzAmm/K6O/fHPIw5eViVly7aj5gjh67ntSuZArVtrxy/Py5V4hkSO8guXKqNz3liJvLbFCqqpfTR/0duArZR0xcnaGc6wIDAQABAoIBAFRuu5YaXxbDq2eS5RzH2Vpakin7+jJOU4wljujL0QnXagC2J2QeJ8l1fT23tieZO4yvrxfVvnFd1aMouHMC5vORqWja4jxEd6ZHWKzxIw6ZbtjZk4eWMvy18KewlFavGyiR2GF0okQ0BMBOPqNhp8JoaMWOsNnKB+GJuBNWUTWtPWNQlbaeI+uIgFywrvZOcQuWqU+9Y5rQa7oKZisufu+z0vd9XyvjXQ/Thnuu9/k1m88EMAMS63zwfIOZm35PPqh1/6aBBcRWquT1X2S8g2hwmMLZJgU91yKtQcIujHXAcvxeK72/dcm8NU6AxM+8aj+821TvcNzJi7he5SGcin0CgYEA4cuxwqRixXz6yDcTv9GpJMULbJGjA+Qf/iSfT+ftBeKbnKgZGzHwOCTu5DMkag3BPjclut4sEt3QPf1cFv5vZvdkOnPeaFxrtoMhSz8ssh8qaOsObCwicel1zdPVTmMw7YzEZV14fdIq3lkHsLy2uWa0imRH0l4xTccmsJiPtU8CgYEAwjQtspxOejCyME+M+hcU3RelD6kaMjICuWGJj8g0OpqdHM7iNVJq78fOlWjntt/ydzfOXVMMVh4AG8dAvlc86iwwsBRsJPVrrrRoSNuAwFbjKisbjlnPbqyclHfUsyQitj19tp//ExH7JaBibzKd6KhqFuQTE1iYLs2mFQAz76UCgYEAsNLu64oGm7frQP345mAPgO8aqjRHIBX3g/Q0GsR61wAGcyElQCnUgHNT7burSa5p5goT7wpsI343xUPzaUJqBY25nRj+VGYEKFL6sM3Rd9B2SuHBUq8hbmmwyraYtiFxwKZbazJO2OHMloHMRvkSc5Dd0/8CS9ld7RYH04Y2DHsCgYEAoKXTK44baP7BWC9mOjc/vgjiNQs4rU8ra7igt7zwX44o63zEKUHNTh7l6DiIfYHRrAcRAahCazaT9makSxAVRs1ZVT7/mq8d7b41Chfx8KmvbuGMAPyQGEhXmoVqAOqigEhrptfBhD/6lkyPQNcJQz2VzOvMT9OYyBa8DWFGlTUCgYAfModz6g2HsYYr37/0ByXHKL0WQQtuAlZzCY9GuDLEok7QLFI/E+bdOHos3goW72Iswo/SO7inlW4S3gojuy+zZhwCO31T9p2Z0Yn0tDK3fkUO32flOLwxCZA99pKkIul3svl6643GqSD1feybmbYRtqoPCTSKSE9vI9T9DkBTvA==" + ], + "keyUse": ["ENC"], + "certificate": [ + "MIICnTCCAYUCBgGVUbFItzANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdzdHVkZW50MB4XDTI1MDMwMTEyMzAyN1oXDTM1MDMwMTEyMzIwN1owEjEQMA4GA1UEAwwHc3R1ZGVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtKYmPz2mYdSF+OntBurQj7X0ce0PMxrJThUgS0fTzQHUpQaWIlfZDqTdZEytknGuY+MsjvRwBSuY/s4f3MvErD9YsriNLAjxuzTCldaT+WO+d8EwtJU6vM9em71z7z2Kz0SoBg5lO1sNP1g+vz/s/S4v/roxR88836D7kL2wYZmugOKGnbAvs7p/5lgsog9eJgfl9NAXgCLMSiWf0nflOJTJJL5qaF8setcSvo+PBAGdfLuxaa5b1I4Bs8wJpvyujv3xzyMOXlYlZcu2o+YI4eu57UrmQK1ba8cvz8uVeIZEjvILlyqjc95Yiby2xQqqqX00f9HbgK2UdMXJ2hnOsCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAHfum0Ymw/qHTpjNeJjJyh5A1N4Z58m/PjuCXafIdDDjuAYpB3/M4bTGZRUvEvv2RuBNv3rONvMR8dRrZwio0/T0aEXnHrEAaCSfVcMy1To8TGGOzgtPMub4YCqXLMCwW5cwIbqT3P58HEqsqEbv7Zp4LtLYZBYXWDF8vM4zEn3CPYxuxRPKlrBUynRKYcwN7+/dbhJKiARpPMIZ5viGbjaTnNE/d/VFdv1q5xm3ItYnShDyJ0REGN18sWleLI6qkW0X22Gcjn38fWjiXDnF0HQYzC2UzMcEo/iLfPxTKbJnc+PPmnszfmCh7mWs5xVGfMOz/Oy8HI121x1ZSriRktA==" + ], + "priority": ["100"], + "algorithm": ["RSA-OAEP"] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "f7d1108f-7994-47e5-81e9-1a88cdbe545c", + "alias": "Account verification options", + "description": "Method with which to verity the existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-email-verification", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false + } + ] + }, + { + "id": "cf40a5d3-bec8-4aef-9658-1b88c6cec561", + "alias": "Browser - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "6820625f-5bb5-4fa2-8539-26a8568265c1", + "alias": "Browser - Conditional Organization", + "description": "Flow to determine if the organization identity-first login is to be used", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "organization", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "66d5e52e-592e-4cef-bfa0-512e90b609ec", + "alias": "Direct Grant - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "b5bed405-b5f2-4839-861c-612501e4c412", + "alias": "First Broker Login - Conditional Organization", + "description": "Flow to determine if the authenticator that adds organization members is to be used", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "idp-add-organization-member", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "dd786e24-e822-43ec-be03-29874eb73737", + "alias": "First broker login - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "8751572f-623e-4bdc-a02c-e92c15a91143", + "alias": "Handle Existing Account", + "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-confirm-link", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Account verification options", + "userSetupAllowed": false + } + ] + }, + { + "id": "61efadf2-a54e-4071-b8c9-83e094525051", + "alias": "Organization", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional Organization", + "userSetupAllowed": false + } + ] + }, + { + "id": "b99c3a7a-8ef7-46b1-b8a1-cb51f8a6e725", + "alias": "Reset - Conditional OTP", + "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "a3bfc2e4-af67-4d3e-851f-3c58bf32be83", + "alias": "User creation or linking", + "description": "Flow for the existing/non-existing user alternatives", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false + } + ] + }, + { + "id": "4cc3bf25-d1b7-43a6-8619-5ed5f2d65aed", + "alias": "Verify Existing Account by Re-authentication", + "description": "Reauthentication of existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "First broker login - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "4e5564ce-87da-4b25-8dcb-062216ceaa8d", + "alias": "browser", + "description": "Browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "identity-provider-redirector", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 25, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 26, + "autheticatorFlow": true, + "flowAlias": "Organization", + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "forms", + "userSetupAllowed": false + } + ] + }, + { + "id": "def90462-5831-4856-b186-05df9e640bbb", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-secret-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-x509", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "f8c9010d-f197-417b-bda1-2993e1a73a21", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "Direct Grant - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "0fb9e2a4-ea0d-453f-a1fe-f000c849fd66", + "alias": "docker auth", + "description": "Used by Docker clients to authenticate against the IDP", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "docker-http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "79a9efc4-1279-4093-8914-92f4e0b02bb4", + "alias": "first broker login", + "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "review profile config", + "authenticator": "idp-review-profile", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "User creation or linking", + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 50, + "autheticatorFlow": true, + "flowAlias": "First Broker Login - Conditional Organization", + "userSetupAllowed": false + } + ] + }, + { + "id": "f855b3a1-6612-4528-94bc-d0793bfda561", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "fb84970b-6f04-4849-a385-792e17c1b8ce", + "alias": "registration", + "description": "Registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "registration form", + "userSetupAllowed": false + } + ] + }, + { + "id": "fcdfd4d4-1c04-487d-aa7c-85e136814274", + "alias": "registration form", + "description": "Registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-password-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 50, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-recaptcha-action", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 60, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-terms-and-conditions", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 70, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "306d8f7d-c12a-46cb-9a68-c6c3f1622f57", + "alias": "reset credentials", + "description": "Reset credentials for a user if they forgot their password or something", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "reset-credentials-choose-user", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-credential-email", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 40, + "autheticatorFlow": true, + "flowAlias": "Reset - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "35a54b09-ff8c-46c4-9f04-1efbb153276c", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "fc1b82d7-593d-4906-a4d9-13220b66b7ce", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "a90543f4-7da7-43bc-8737-7e58dd190014", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + } + ], + "requiredActions": [ + { + "alias": "CONFIGURE_TOTP", + "name": "Configure OTP", + "providerId": "CONFIGURE_TOTP", + "enabled": true, + "defaultAction": false, + "priority": 10, + "config": {} + }, + { + "alias": "TERMS_AND_CONDITIONS", + "name": "Terms and Conditions", + "providerId": "TERMS_AND_CONDITIONS", + "enabled": false, + "defaultAction": false, + "priority": 20, + "config": {} + }, + { + "alias": "UPDATE_PASSWORD", + "name": "Update Password", + "providerId": "UPDATE_PASSWORD", + "enabled": true, + "defaultAction": false, + "priority": 30, + "config": {} + }, + { + "alias": "UPDATE_PROFILE", + "name": "Update Profile", + "providerId": "UPDATE_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 40, + "config": {} + }, + { + "alias": "VERIFY_EMAIL", + "name": "Verify Email", + "providerId": "VERIFY_EMAIL", + "enabled": true, + "defaultAction": false, + "priority": 50, + "config": {} + }, + { + "alias": "delete_account", + "name": "Delete Account", + "providerId": "delete_account", + "enabled": false, + "defaultAction": false, + "priority": 60, + "config": {} + }, + { + "alias": "webauthn-register", + "name": "Webauthn Register", + "providerId": "webauthn-register", + "enabled": true, + "defaultAction": false, + "priority": 70, + "config": {} + }, + { + "alias": "webauthn-register-passwordless", + "name": "Webauthn Register Passwordless", + "providerId": "webauthn-register-passwordless", + "enabled": true, + "defaultAction": false, + "priority": 80, + "config": {} + }, + { + "alias": "VERIFY_PROFILE", + "name": "Verify Profile", + "providerId": "VERIFY_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 90, + "config": {} + }, + { + "alias": "delete_credential", + "name": "Delete Credential", + "providerId": "delete_credential", + "enabled": true, + "defaultAction": false, + "priority": 100, + "config": {} + }, + { + "alias": "update_user_locale", + "name": "Update User Locale", + "providerId": "update_user_locale", + "enabled": true, + "defaultAction": false, + "priority": 1000, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "firstBrokerLoginFlow": "first broker login", + "attributes": { + "cibaBackchannelTokenDeliveryMode": "poll", + "cibaExpiresIn": "120", + "cibaAuthRequestedUserHint": "login_hint", + "oauth2DeviceCodeLifespan": "600", + "oauth2DevicePollingInterval": "5", + "parRequestUriLifespan": "60", + "cibaInterval": "5", + "realmReusableOtpCode": "false" + }, + "keycloakVersion": "26.1.3", + "userManagedAccessAllowed": false, + "organizationsEnabled": false, + "verifiableCredentialsEnabled": false, + "adminPermissionsEnabled": false, + "clientProfiles": { + "profiles": [] + }, + "clientPolicies": { + "policies": [] } - }, - "groups" : [ ], - "defaultRole" : { - "id" : "b3bf9566-098c-4167-9cce-f64c720ca511", - "name" : "default-roles-student", - "description" : "${role_default-roles}", - "composite" : true, - "clientRole" : false, - "containerId" : "08a7ab0a-d483-4103-a781-76013864bf50" - }, - "requiredCredentials" : [ "password" ], - "otpPolicyType" : "totp", - "otpPolicyAlgorithm" : "HmacSHA1", - "otpPolicyInitialCounter" : 0, - "otpPolicyDigits" : 6, - "otpPolicyLookAheadWindow" : 1, - "otpPolicyPeriod" : 30, - "otpPolicyCodeReusable" : false, - "otpSupportedApplications" : [ "totpAppFreeOTPName", "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName" ], - "localizationTexts" : { }, - "webAuthnPolicyRpEntityName" : "keycloak", - "webAuthnPolicySignatureAlgorithms" : [ "ES256", "RS256" ], - "webAuthnPolicyRpId" : "", - "webAuthnPolicyAttestationConveyancePreference" : "not specified", - "webAuthnPolicyAuthenticatorAttachment" : "not specified", - "webAuthnPolicyRequireResidentKey" : "not specified", - "webAuthnPolicyUserVerificationRequirement" : "not specified", - "webAuthnPolicyCreateTimeout" : 0, - "webAuthnPolicyAvoidSameAuthenticatorRegister" : false, - "webAuthnPolicyAcceptableAaguids" : [ ], - "webAuthnPolicyExtraOrigins" : [ ], - "webAuthnPolicyPasswordlessRpEntityName" : "keycloak", - "webAuthnPolicyPasswordlessSignatureAlgorithms" : [ "ES256", "RS256" ], - "webAuthnPolicyPasswordlessRpId" : "", - "webAuthnPolicyPasswordlessAttestationConveyancePreference" : "not specified", - "webAuthnPolicyPasswordlessAuthenticatorAttachment" : "not specified", - "webAuthnPolicyPasswordlessRequireResidentKey" : "not specified", - "webAuthnPolicyPasswordlessUserVerificationRequirement" : "not specified", - "webAuthnPolicyPasswordlessCreateTimeout" : 0, - "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false, - "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ], - "webAuthnPolicyPasswordlessExtraOrigins" : [ ], - "users" : [ { - "id" : "79e9a395-d7e4-48c9-a06e-702435bae290", - "username" : "testleerling1", - "firstName" : "Gerald", - "lastName" : "Schmittinger", - "email" : "Gerald.Schmittinger@UGent.be", - "emailVerified" : false, - "createdTimestamp" : 1740858528405, - "enabled" : true, - "totp" : false, - "credentials" : [ { - "id" : "c31a708f-8614-4144-a25f-3e976c9035ce", - "type" : "password", - "userLabel" : "My password", - "createdDate" : 1740858548515, - "secretData" : "{\"value\":\"yDKIAbZPuVXBGk4zjiqE/YFcPDm1vjXLwTrPUrvMhXY=\",\"salt\":\"tYvjd4mhV2UWeOUssK01Cw==\",\"additionalParameters\":{}}", - "credentialData" : "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}" - } ], - "disableableCredentialTypes" : [ ], - "requiredActions" : [ ], - "realmRoles" : [ "default-roles-student" ], - "notBefore" : 0, - "groups" : [ ] - } ], - "scopeMappings" : [ { - "clientScope" : "offline_access", - "roles" : [ "offline_access" ] - } ], - "clientScopeMappings" : { - "account" : [ { - "client" : "account-console", - "roles" : [ "manage-account", "view-groups" ] - } ] - }, - "clients" : [ { - "id" : "b3a22454-d780-4093-8333-9be6f6cd5855", - "clientId" : "account", - "name" : "${client_account}", - "rootUrl" : "${authBaseUrl}", - "baseUrl" : "/realms/student/account/", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ "/realms/student/account/*" ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "false", - "post.logout.redirect.uris" : "+" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - }, { - "id" : "854c221b-630c-4cc3-9365-bd254246dd69", - "clientId" : "account-console", - "name" : "${client_account-console}", - "rootUrl" : "${authBaseUrl}", - "baseUrl" : "/realms/student/account/", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ "/realms/student/account/*" ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "false", - "post.logout.redirect.uris" : "+", - "pkce.code.challenge.method" : "S256" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "protocolMappers" : [ { - "id" : "f33b40fe-bb9e-4254-ada9-f98dd203641b", - "name" : "audience resolve", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-audience-resolve-mapper", - "consentRequired" : false, - "config" : { } - } ], - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - }, { - "id" : "9449aa8b-d5cc-4b9f-bb01-be1e5a896f2f", - "clientId" : "admin-cli", - "name" : "${client_admin-cli}", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : false, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : true, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "false", - "client.use.lightweight.access.token.enabled" : "true" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : true, - "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - }, { - "id" : "befe3d72-8102-49a6-8268-bce6def58159", - "clientId" : "broker", - "name" : "${client_broker}", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : true, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : false, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "true" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - }, { - "id" : "714243ae-72cc-4c26-842a-047357b5919a", - "clientId" : "dwengo", - "name" : "Dwengo", - "description" : "", - "rootUrl" : "http://localhost:5173", - "adminUrl" : "http://localhost:5173", - "baseUrl" : "/", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-jwt", - "redirectUris" : [ "urn:ietf:wg:oauth:2.0:oob", "http://localhost:5173/*", "http://localhost:5173" ], - "webOrigins" : [ "+" ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : true, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : true, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "false", - "oidc.ciba.grant.enabled" : "false", - "client.secret.creation.time" : "1740860818", - "backchannel.logout.session.required" : "true", - "token.endpoint.auth.signing.alg" : "RS256", - "post.logout.redirect.uris" : "+", - "frontchannel.logout.session.required" : "true", - "oauth2.device.authorization.grant.enabled" : "false", - "display.on.consent.screen" : "false", - "backchannel.logout.revoke.offline.tokens" : "false" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : true, - "nodeReRegistrationTimeout" : -1, - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - }, { - "id" : "0b06aaa3-717d-4a52-ab46-295a6571b642", - "clientId" : "realm-management", - "name" : "${client_realm-management}", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : true, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : false, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "true" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - }, { - "id" : "dfc7248c-3794-4e3b-aed2-3ee553cd0feb", - "clientId" : "security-admin-console", - "name" : "${client_security-admin-console}", - "rootUrl" : "${authAdminUrl}", - "baseUrl" : "/admin/student/console/", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ "/admin/student/console/*" ], - "webOrigins" : [ "+" ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "false", - "client.use.lightweight.access.token.enabled" : "true", - "post.logout.redirect.uris" : "+", - "pkce.code.challenge.method" : "S256" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : true, - "nodeReRegistrationTimeout" : 0, - "protocolMappers" : [ { - "id" : "9e9ff295-30c9-43f1-a11a-773724709c07", - "name" : "locale", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "locale", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "locale", - "jsonType.label" : "String" - } - } ], - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - } ], - "clientScopes" : [ { - "id" : "0721b27a-284f-4e6d-af70-b6f190ebdcd4", - "name" : "email", - "description" : "OpenID Connect built-in scope: email", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "consent.screen.text" : "${emailScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "d256bdc1-8983-41e0-b8fa-fcf45653045e", - "name" : "email verified", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-property-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "emailVerified", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "email_verified", - "jsonType.label" : "boolean" - } - }, { - "id" : "651c2415-db30-40ed-bdef-745b6ea744ed", - "name" : "email", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "email", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "email", - "jsonType.label" : "String" - } - } ] - }, { - "id" : "573f6eea-7626-44fe-9855-50f15c3939ba", - "name" : "web-origins", - "description" : "OpenID Connect scope for add allowed web origins to the access token", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "consent.screen.text" : "", - "display.on.consent.screen" : "false" - }, - "protocolMappers" : [ { - "id" : "3489c748-3cc7-4350-9351-2955fc7084ba", - "name" : "allowed web origins", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-allowed-origins-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "access.token.claim" : "true" - } - } ] - }, { - "id" : "00afe548-c677-4595-8478-16f752c2713a", - "name" : "offline_access", - "description" : "OpenID Connect built-in scope: offline_access", - "protocol" : "openid-connect", - "attributes" : { - "consent.screen.text" : "${offlineAccessScopeConsentText}", - "display.on.consent.screen" : "true" - } - }, { - "id" : "1448ed2b-ec1d-4bf4-a8b7-00cb85459289", - "name" : "address", - "description" : "OpenID Connect built-in scope: address", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "consent.screen.text" : "${addressScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "12d491b6-5d74-4168-ac5c-517ebc2f1de4", - "name" : "address", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-address-mapper", - "consentRequired" : false, - "config" : { - "user.attribute.formatted" : "formatted", - "user.attribute.country" : "country", - "introspection.token.claim" : "true", - "user.attribute.postal_code" : "postal_code", - "userinfo.token.claim" : "true", - "user.attribute.street" : "street", - "id.token.claim" : "true", - "user.attribute.region" : "region", - "access.token.claim" : "true", - "user.attribute.locality" : "locality" - } - } ] - }, { - "id" : "52223fb1-9651-4cdf-8317-a1301d4042f7", - "name" : "organization", - "description" : "Additional claims about the organization a subject belongs to", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "consent.screen.text" : "${organizationScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "dccc4214-ece6-4235-8119-ee8cb954c29a", - "name" : "organization", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-organization-membership-mapper", - "consentRequired" : false, - "config" : { - "id.token.claim" : "true", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "organization", - "jsonType.label" : "String", - "multivalued" : "true" - } - } ] - }, { - "id" : "8be22542-e327-4a25-8265-a34a29607d1b", - "name" : "service_account", - "description" : "Specific scope for a client enabled for service accounts", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "display.on.consent.screen" : "false" - }, - "protocolMappers" : [ { - "id" : "cf89064a-0af3-4a4b-a838-3528a8f4d780", - "name" : "Client IP Address", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usersessionmodel-note-mapper", - "consentRequired" : false, - "config" : { - "user.session.note" : "clientAddress", - "id.token.claim" : "true", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "clientAddress", - "jsonType.label" : "String" - } - }, { - "id" : "dc0f77e6-cc20-4c0a-baf3-f45046d749d1", - "name" : "Client ID", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usersessionmodel-note-mapper", - "consentRequired" : false, - "config" : { - "user.session.note" : "client_id", - "id.token.claim" : "true", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "client_id", - "jsonType.label" : "String" - } - }, { - "id" : "d63fd29a-3613-4529-a8e4-3a7d7e9f5802", - "name" : "Client Host", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usersessionmodel-note-mapper", - "consentRequired" : false, - "config" : { - "user.session.note" : "clientHost", - "id.token.claim" : "true", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "clientHost", - "jsonType.label" : "String" - } - } ] - }, { - "id" : "d9079603-62b7-4680-9d01-950daae75d6b", - "name" : "saml_organization", - "description" : "Organization Membership", - "protocol" : "saml", - "attributes" : { - "display.on.consent.screen" : "false" - }, - "protocolMappers" : [ { - "id" : "d826fc58-b006-49ad-93dc-a76700e800df", - "name" : "organization", - "protocol" : "saml", - "protocolMapper" : "saml-organization-membership-mapper", - "consentRequired" : false, - "config" : { } - } ] - }, { - "id" : "171d8267-87da-4a4b-9346-d901d470248b", - "name" : "phone", - "description" : "OpenID Connect built-in scope: phone", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "consent.screen.text" : "${phoneScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "f8bb18d4-af9d-49b0-a61f-cc81887870cd", - "name" : "phone number", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "phoneNumber", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "phone_number", - "jsonType.label" : "String" - } - }, { - "id" : "88a2c658-9b61-40a2-abd5-69c501286031", - "name" : "phone number verified", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "phoneNumberVerified", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "phone_number_verified", - "jsonType.label" : "boolean" - } - } ] - }, { - "id" : "ea3b84ac-a91f-4a3d-be4e-893e11eaf4a1", - "name" : "acr", - "description" : "OpenID Connect scope for add acr (authentication context class reference) to the token", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "display.on.consent.screen" : "false" - }, - "protocolMappers" : [ { - "id" : "152d66d4-524f-47f1-a592-be3a0c043a4f", - "name" : "acr loa level", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-acr-mapper", - "consentRequired" : false, - "config" : { - "id.token.claim" : "true", - "introspection.token.claim" : "true", - "access.token.claim" : "true" - } - } ] - }, { - "id" : "2fc1ad0d-1065-4196-8d1b-c61525c9425d", - "name" : "microprofile-jwt", - "description" : "Microprofile - JWT built-in scope", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "display.on.consent.screen" : "false" - }, - "protocolMappers" : [ { - "id" : "9d537486-f6bf-4856-91fc-ca3acaa78814", - "name" : "upn", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "username", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "upn", - "jsonType.label" : "String" - } - }, { - "id" : "55425438-4111-47a0-9a36-fec9dbbc6a8a", - "name" : "groups", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-realm-role-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "multivalued" : "true", - "user.attribute" : "foo", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "groups", - "jsonType.label" : "String" - } - } ] - }, { - "id" : "0d186f4e-ef6d-4fbc-9593-081e0d5ad171", - "name" : "profile", - "description" : "OpenID Connect built-in scope: profile", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "consent.screen.text" : "${profileScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "bb8bb550-2db6-4631-97dc-1d115d0e3034", - "name" : "given name", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "firstName", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "given_name", - "jsonType.label" : "String" - } - }, { - "id" : "c942089b-2898-4052-a64d-85b61e27aaa4", - "name" : "username", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "username", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "preferred_username", - "jsonType.label" : "String" - } - }, { - "id" : "5ff3a9ca-7036-458c-b0dc-41216292d210", - "name" : "updated at", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "updatedAt", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "updated_at", - "jsonType.label" : "long" - } - }, { - "id" : "41f93d62-4074-4373-a270-9bdf1e298cb5", - "name" : "website", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "website", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "website", - "jsonType.label" : "String" - } - }, { - "id" : "ffec7d63-0f78-41ea-8023-6c7c64661b34", - "name" : "locale", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "locale", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "locale", - "jsonType.label" : "String" - } - }, { - "id" : "4a514ae7-d29f-4979-8df9-a97b36a81a96", - "name" : "profile", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "profile", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "profile", - "jsonType.label" : "String" - } - }, { - "id" : "286e349b-cb9f-41b1-b9dc-d787f13e9d99", - "name" : "nickname", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "nickname", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "nickname", - "jsonType.label" : "String" - } - }, { - "id" : "f5177603-55b1-4abe-aee6-b1e5a05e37f6", - "name" : "full name", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-full-name-mapper", - "consentRequired" : false, - "config" : { - "id.token.claim" : "true", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "userinfo.token.claim" : "true" - } - }, { - "id" : "a31114d7-05fc-40c1-9ea8-6977f6f0bec5", - "name" : "zoneinfo", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "zoneinfo", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "zoneinfo", - "jsonType.label" : "String" - } - }, { - "id" : "8884be77-648d-4083-b0cf-57130162c8dc", - "name" : "gender", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "gender", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "gender", - "jsonType.label" : "String" - } - }, { - "id" : "61840434-c79f-455a-a914-117977197304", - "name" : "family name", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "lastName", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "family_name", - "jsonType.label" : "String" - } - }, { - "id" : "1f40ff0b-1664-4259-846b-ab707c76d33b", - "name" : "middle name", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "middleName", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "middle_name", - "jsonType.label" : "String" - } - }, { - "id" : "8534d400-8a81-4ae3-b51f-78b93e5a2045", - "name" : "picture", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "picture", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "picture", - "jsonType.label" : "String" - } - }, { - "id" : "82a0e240-0824-41b9-b6e8-856a72d1e930", - "name" : "birthdate", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "birthdate", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "birthdate", - "jsonType.label" : "String" - } - } ] - }, { - "id" : "a5cedc85-d9e9-42e1-9ea3-ff37d21d5e27", - "name" : "role_list", - "description" : "SAML role list", - "protocol" : "saml", - "attributes" : { - "consent.screen.text" : "${samlRoleListScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "19009128-590f-4bc9-80de-c9ba4aae822d", - "name" : "role list", - "protocol" : "saml", - "protocolMapper" : "saml-role-list-mapper", - "consentRequired" : false, - "config" : { - "single" : "false", - "attribute.nameformat" : "Basic", - "attribute.name" : "Role" - } - } ] - }, { - "id" : "3b6bb88b-c833-4bb5-9bd0-95831aa2ad0d", - "name" : "basic", - "description" : "OpenID Connect scope for add all basic claims to the token", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "display.on.consent.screen" : "false" - }, - "protocolMappers" : [ { - "id" : "ce925803-aec2-47cb-a3b9-4bef12c80367", - "name" : "sub", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-sub-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "access.token.claim" : "true" - } - }, { - "id" : "58729b3a-3816-460e-bf2e-d0d2206c1830", - "name" : "auth_time", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usersessionmodel-note-mapper", - "consentRequired" : false, - "config" : { - "user.session.note" : "AUTH_TIME", - "id.token.claim" : "true", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "auth_time", - "jsonType.label" : "long" - } - } ] - }, { - "id" : "7aa2d936-3edb-45e5-bae0-b4a618d06371", - "name" : "roles", - "description" : "OpenID Connect scope for add user roles to the access token", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "consent.screen.text" : "${rolesScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "a9d1e8e2-ca10-4904-8a42-7708b0bfdefa", - "name" : "client roles", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-client-role-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "foo", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "resource_access.${client_id}.roles", - "jsonType.label" : "String", - "multivalued" : "true" - } - }, { - "id" : "1f217073-ad43-483b-b0d5-f3ca4c74282f", - "name" : "realm roles", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-realm-role-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "foo", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "realm_access.roles", - "jsonType.label" : "String", - "multivalued" : "true" - } - }, { - "id" : "61b0a069-8b67-4692-bcca-66a197b230eb", - "name" : "audience resolve", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-audience-resolve-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "access.token.claim" : "true" - } - } ] - } ], - "defaultDefaultClientScopes" : [ "role_list", "saml_organization", "profile", "email", "roles", "web-origins", "acr", "basic" ], - "defaultOptionalClientScopes" : [ "offline_access", "address", "phone", "microprofile-jwt", "organization" ], - "browserSecurityHeaders" : { - "contentSecurityPolicyReportOnly" : "", - "xContentTypeOptions" : "nosniff", - "referrerPolicy" : "no-referrer", - "xRobotsTag" : "none", - "xFrameOptions" : "SAMEORIGIN", - "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", - "xXSSProtection" : "1; mode=block", - "strictTransportSecurity" : "max-age=31536000; includeSubDomains" - }, - "smtpServer" : { }, - "eventsEnabled" : false, - "eventsListeners" : [ "jboss-logging" ], - "enabledEventTypes" : [ ], - "adminEventsEnabled" : false, - "adminEventsDetailsEnabled" : false, - "identityProviders" : [ ], - "identityProviderMappers" : [ ], - "components" : { - "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ { - "id" : "9eac5531-7f25-493f-a721-6c5e65cd34c2", - "name" : "Max Clients Limit", - "providerId" : "max-clients", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { - "max-clients" : [ "200" ] - } - }, { - "id" : "d9319a22-4c67-4b08-822f-4162a1ee01bc", - "name" : "Allowed Client Scopes", - "providerId" : "allowed-client-templates", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { - "allow-default-scopes" : [ "true" ] - } - }, { - "id" : "21456c8e-7f6b-4e49-a3e1-bea7f900e2fb", - "name" : "Consent Required", - "providerId" : "consent-required", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { } - }, { - "id" : "4872e99b-b55b-4e13-8a93-63e853289cac", - "name" : "Full Scope Disabled", - "providerId" : "scope", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { } - }, { - "id" : "a118a194-09f5-435d-9d4b-363813413167", - "name" : "Trusted Hosts", - "providerId" : "trusted-hosts", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { - "host-sending-registration-request-must-match" : [ "true" ], - "client-uris-must-match" : [ "true" ] - } - }, { - "id" : "e32b1e26-6571-4b0c-a205-0fbb3de44384", - "name" : "Allowed Client Scopes", - "providerId" : "allowed-client-templates", - "subType" : "authenticated", - "subComponents" : { }, - "config" : { - "allow-default-scopes" : [ "true" ] - } - }, { - "id" : "9dbe6752-9978-42a3-9210-9ec166140de2", - "name" : "Allowed Protocol Mapper Types", - "providerId" : "allowed-protocol-mappers", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { - "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper", "saml-role-list-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper" ] - } - }, { - "id" : "7027b3f4-d877-4814-ac78-f1edb8eb89b0", - "name" : "Allowed Protocol Mapper Types", - "providerId" : "allowed-protocol-mappers", - "subType" : "authenticated", - "subComponents" : { }, - "config" : { - "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper", "saml-user-property-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper" ] - } - } ], - "org.keycloak.keys.KeyProvider" : [ { - "id" : "819cfc66-a997-4747-9d90-a7f0c09774bf", - "name" : "aes-generated", - "providerId" : "aes-generated", - "subComponents" : { }, - "config" : { - "kid" : [ "eb74df73-3f34-457d-95c7-5ad909107703" ], - "secret" : [ "1K8IJiDODmotHJPStrXhtA" ], - "priority" : [ "100" ] - } - }, { - "id" : "299857cd-52a4-4981-8171-02e7d8f12960", - "name" : "rsa-generated", - "providerId" : "rsa-generated", - "subComponents" : { }, - "config" : { - "privateKey" : [ "MIIEpAIBAAKCAQEA1MRmAT/yImkVfPMBxC0QHdC4DQfuWUTjKeEku+gMI9jX5ChUzzzVugcvZWmxBNcvOz7p6R8EdPllZKIwFSH5WvQ1w1VIgQwIlYfpi/pknfftLd66MI2fXrQK19dRTeQRivEf39GTfBQ2Xc7y1q7zbMo5TVxATJ3DgPi13dYO7zVPpGTiQQeYiezlcBedyGe4cS1g6oBoaVif1QPY1Ni2vEjJhczNMGI408tIFws8G04Tlno814nT0ysdflUSGcRUku41NtfM9hr57LQ459sGYho8Pn11lDuiUWkomJv0y3GJ1wFBvQbDvI+6QvEdFu0GxShrlcORrNmj3BwOOLhB7wIDAQABAoIBAA6zrXq7oO8YxMfYANC97mWpBPa9jA42EN5VdNTZIXGeq7hTwxx4zynmEjPXPEih190nqUEXCBdPHl74SAtFyDWtN0PSkkp8euFePViTSj2SIpzvTX1KY+9G0JL+iVsw/bdUlwe/swm5WdJcmPIVr7NeO9xpGfZRVm+EgAieoHSN4Z7g20wLbVz1fya+6O5Hy+IGezamIA4tchk+4hyiVpSh2TcdjkJJZWOlHKPkwWU/MYQbJibuea5jLoWA39NIqV2l5GT0SoCbffGJNb9CMTTGmXoK5zNwHhG+M0a4eP1vbFDLaoDne86JySmTdv/WrTFFa3veelw2K8PHDybuB70CgYEA/gbxqLZYkJcEpqsjM/XcISFJ09icJLKl5r2l/Dm4Qq587QniQYribX/PPLfDhgVwPByQe3rccq9FoiILycTdIwgSMTsg5fzvbLJTqMAcl2r0zJgHVIDc6iXnytuE0FffKN0kSKL1C4d6n6vKoCGvOcZoXK5jxgzpY8lasvKxhCsCgYEA1mtr7CDYY3qPmTu4/Uz6cFgX8RDMZZ11AQQXNMsKHIu5C4xLeYmJMlpt0y4h52/NWRzh2svdw3SEZTCfP1WVC7StfP8KD8QdwVkQlY5EGkiz9uRtEgwk8chkOTIm2JedeRL6YWlTgnH9PIuGq84OOnEbFjVN3Lbx3N1QuQfVA00CgYEAybA1uuBcXSCqfrIuVxkD2AIYHe1DvBdjhVpaKXKii78CTSmlzKg6svnhTrIQuZ4jyHZdeMzJrvzeaqZheaemdCP6XcA2lKRIbKMBrWAq00YGa1LhrwRJYlcKPJQiVVEPS+CY6FsJ+Edu4suBK7bS6ypOvhdv/FVQEPxT2PS8YNUCgYEAxwJ+8XNuw63ud9+Zi+gVjY4F8qWPwESLYz0DuOk2YlZAknpNVumTYBvUUSxBJYh8RFhtO+D53D5Z331oYKUzJ+EzII+qLAXvRBRBMz4O8YJHHkDXBugkphBDDV8B9QeLjeNSZnUWoDziOH6bqPwf8pgl9s/Ui6V1CHSVRpcBWwUCgYA2kMgu7qS5kLtUWySPzW4nTKwhN+HFTIbRrNrECxXmxroigTEyfBFuNR5QaeYYrAtqgY1m5Lev//2GnWM7dAr7hewj6qfGszrvegHsqMs4cakVqEOtbrWxL+WtWPaIdjJ+x7ZoMnZxZDg3ysemybNHHwSyBsp1TDc+glzmMtJtLA==" ], - "keyUse" : [ "SIG" ], - "certificate" : [ "MIICnTCCAYUCBgGVUbFIeTANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdzdHVkZW50MB4XDTI1MDMwMTEyMzAyN1oXDTM1MDMwMTEyMzIwN1owEjEQMA4GA1UEAwwHc3R1ZGVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANTEZgE/8iJpFXzzAcQtEB3QuA0H7llE4ynhJLvoDCPY1+QoVM881boHL2VpsQTXLzs+6ekfBHT5ZWSiMBUh+Vr0NcNVSIEMCJWH6Yv6ZJ337S3eujCNn160CtfXUU3kEYrxH9/Rk3wUNl3O8tau82zKOU1cQEydw4D4td3WDu81T6Rk4kEHmIns5XAXnchnuHEtYOqAaGlYn9UD2NTYtrxIyYXMzTBiONPLSBcLPBtOE5Z6PNeJ09MrHX5VEhnEVJLuNTbXzPYa+ey0OOfbBmIaPD59dZQ7olFpKJib9MtxidcBQb0Gw7yPukLxHRbtBsUoa5XDkazZo9wcDji4Qe8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAedqvKOBsz4IKKzkWHIQnN5H8dQKnuPUMdWewOwmMGIUdBU9k6aS+y+BB7mugF/Hnr8Lw5d2AHwVLj2VyP4Pq0d2My3Ihxi0vr6sSfxVHuD9y/a7FxDGVTkCvmy5DOmpF/kdNnL9xG5ZivHaucnrIHHGMcQCdbWAaac0qPZihv9pdMZFMtI3aiBO5jVJ7KP8iLNKsshg60mxCOPzauMVXi+rqqqhGAgMKAL4hjjvdIKTLWwmthnmAlGqlTk/7H82hS9aKygufXszXWdFAYhX/r8/hjyc+6zJUvkG20uRWnkR35gya7jQoZ2O6OvkQf0mgSvzgIP3xoYV2uKYD03wINg==" ], - "priority" : [ "100" ] - } - }, { - "id" : "3d6bfeeb-fa86-435e-8c39-6f547a0f4a38", - "name" : "hmac-generated-hs512", - "providerId" : "hmac-generated", - "subComponents" : { }, - "config" : { - "kid" : [ "176e970f-5915-4d27-8233-8fab6d7ad947" ], - "secret" : [ "sXeOdtyIPpH_kcZWikHFjTur9yWok0QUwKi95l8wHp6kTVX9vhoZL2siNHRoFnn8tFgT4JZbR0bMsD57qAXlmVjA830Ny_GZdhL_PFWQh7JYMEJrl-1nyLy_SReQXRtq_q9tKUafUZqeYSKBlUYZ7D4jNRJ4-uniq80Ger-4ee0" ], - "priority" : [ "100" ], - "algorithm" : [ "HS512" ] - } - }, { - "id" : "df1247b5-041e-4ae8-b7fc-26c4b6f5ff67", - "name" : "rsa-enc-generated", - "providerId" : "rsa-enc-generated", - "subComponents" : { }, - "config" : { - "privateKey" : [ "MIIEpAIBAAKCAQEAq0piY/PaZh1IX46e0G6tCPtfRx7Q8zGslOFSBLR9PNAdSlBpYiV9kOpN1kTK2Sca5j4yyO9HAFK5j+zh/cy8SsP1iyuI0sCPG7NMKV1pP5Y753wTC0lTq8z16bvXPvPYrPRKgGDmU7Ww0/WD6/P+z9Li/+ujFHzzzfoPuQvbBhma6A4oadsC+zun/mWCyiD14mB+X00BeAIsxKJZ/Sd+U4lMkkvmpoXyx61xK+j48EAZ18u7FprlvUjgGzzAmm/K6O/fHPIw5eViVly7aj5gjh67ntSuZArVtrxy/Py5V4hkSO8guXKqNz3liJvLbFCqqpfTR/0duArZR0xcnaGc6wIDAQABAoIBAFRuu5YaXxbDq2eS5RzH2Vpakin7+jJOU4wljujL0QnXagC2J2QeJ8l1fT23tieZO4yvrxfVvnFd1aMouHMC5vORqWja4jxEd6ZHWKzxIw6ZbtjZk4eWMvy18KewlFavGyiR2GF0okQ0BMBOPqNhp8JoaMWOsNnKB+GJuBNWUTWtPWNQlbaeI+uIgFywrvZOcQuWqU+9Y5rQa7oKZisufu+z0vd9XyvjXQ/Thnuu9/k1m88EMAMS63zwfIOZm35PPqh1/6aBBcRWquT1X2S8g2hwmMLZJgU91yKtQcIujHXAcvxeK72/dcm8NU6AxM+8aj+821TvcNzJi7he5SGcin0CgYEA4cuxwqRixXz6yDcTv9GpJMULbJGjA+Qf/iSfT+ftBeKbnKgZGzHwOCTu5DMkag3BPjclut4sEt3QPf1cFv5vZvdkOnPeaFxrtoMhSz8ssh8qaOsObCwicel1zdPVTmMw7YzEZV14fdIq3lkHsLy2uWa0imRH0l4xTccmsJiPtU8CgYEAwjQtspxOejCyME+M+hcU3RelD6kaMjICuWGJj8g0OpqdHM7iNVJq78fOlWjntt/ydzfOXVMMVh4AG8dAvlc86iwwsBRsJPVrrrRoSNuAwFbjKisbjlnPbqyclHfUsyQitj19tp//ExH7JaBibzKd6KhqFuQTE1iYLs2mFQAz76UCgYEAsNLu64oGm7frQP345mAPgO8aqjRHIBX3g/Q0GsR61wAGcyElQCnUgHNT7burSa5p5goT7wpsI343xUPzaUJqBY25nRj+VGYEKFL6sM3Rd9B2SuHBUq8hbmmwyraYtiFxwKZbazJO2OHMloHMRvkSc5Dd0/8CS9ld7RYH04Y2DHsCgYEAoKXTK44baP7BWC9mOjc/vgjiNQs4rU8ra7igt7zwX44o63zEKUHNTh7l6DiIfYHRrAcRAahCazaT9makSxAVRs1ZVT7/mq8d7b41Chfx8KmvbuGMAPyQGEhXmoVqAOqigEhrptfBhD/6lkyPQNcJQz2VzOvMT9OYyBa8DWFGlTUCgYAfModz6g2HsYYr37/0ByXHKL0WQQtuAlZzCY9GuDLEok7QLFI/E+bdOHos3goW72Iswo/SO7inlW4S3gojuy+zZhwCO31T9p2Z0Yn0tDK3fkUO32flOLwxCZA99pKkIul3svl6643GqSD1feybmbYRtqoPCTSKSE9vI9T9DkBTvA==" ], - "keyUse" : [ "ENC" ], - "certificate" : [ "MIICnTCCAYUCBgGVUbFItzANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdzdHVkZW50MB4XDTI1MDMwMTEyMzAyN1oXDTM1MDMwMTEyMzIwN1owEjEQMA4GA1UEAwwHc3R1ZGVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtKYmPz2mYdSF+OntBurQj7X0ce0PMxrJThUgS0fTzQHUpQaWIlfZDqTdZEytknGuY+MsjvRwBSuY/s4f3MvErD9YsriNLAjxuzTCldaT+WO+d8EwtJU6vM9em71z7z2Kz0SoBg5lO1sNP1g+vz/s/S4v/roxR88836D7kL2wYZmugOKGnbAvs7p/5lgsog9eJgfl9NAXgCLMSiWf0nflOJTJJL5qaF8setcSvo+PBAGdfLuxaa5b1I4Bs8wJpvyujv3xzyMOXlYlZcu2o+YI4eu57UrmQK1ba8cvz8uVeIZEjvILlyqjc95Yiby2xQqqqX00f9HbgK2UdMXJ2hnOsCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAHfum0Ymw/qHTpjNeJjJyh5A1N4Z58m/PjuCXafIdDDjuAYpB3/M4bTGZRUvEvv2RuBNv3rONvMR8dRrZwio0/T0aEXnHrEAaCSfVcMy1To8TGGOzgtPMub4YCqXLMCwW5cwIbqT3P58HEqsqEbv7Zp4LtLYZBYXWDF8vM4zEn3CPYxuxRPKlrBUynRKYcwN7+/dbhJKiARpPMIZ5viGbjaTnNE/d/VFdv1q5xm3ItYnShDyJ0REGN18sWleLI6qkW0X22Gcjn38fWjiXDnF0HQYzC2UzMcEo/iLfPxTKbJnc+PPmnszfmCh7mWs5xVGfMOz/Oy8HI121x1ZSriRktA==" ], - "priority" : [ "100" ], - "algorithm" : [ "RSA-OAEP" ] - } - } ] - }, - "internationalizationEnabled" : false, - "supportedLocales" : [ ], - "authenticationFlows" : [ { - "id" : "f7d1108f-7994-47e5-81e9-1a88cdbe545c", - "alias" : "Account verification options", - "description" : "Method with which to verity the existing account", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "idp-email-verification", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "ALTERNATIVE", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "Verify Existing Account by Re-authentication", - "userSetupAllowed" : false - } ] - }, { - "id" : "cf40a5d3-bec8-4aef-9658-1b88c6cec561", - "alias" : "Browser - Conditional OTP", - "description" : "Flow to determine if the OTP is required for the authentication", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "auth-otp-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "6820625f-5bb5-4fa2-8539-26a8568265c1", - "alias" : "Browser - Conditional Organization", - "description" : "Flow to determine if the organization identity-first login is to be used", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "organization", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "66d5e52e-592e-4cef-bfa0-512e90b609ec", - "alias" : "Direct Grant - Conditional OTP", - "description" : "Flow to determine if the OTP is required for the authentication", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "direct-grant-validate-otp", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "b5bed405-b5f2-4839-861c-612501e4c412", - "alias" : "First Broker Login - Conditional Organization", - "description" : "Flow to determine if the authenticator that adds organization members is to be used", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "idp-add-organization-member", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "dd786e24-e822-43ec-be03-29874eb73737", - "alias" : "First broker login - Conditional OTP", - "description" : "Flow to determine if the OTP is required for the authentication", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "auth-otp-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "8751572f-623e-4bdc-a02c-e92c15a91143", - "alias" : "Handle Existing Account", - "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "idp-confirm-link", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "Account verification options", - "userSetupAllowed" : false - } ] - }, { - "id" : "61efadf2-a54e-4071-b8c9-83e094525051", - "alias" : "Organization", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 10, - "autheticatorFlow" : true, - "flowAlias" : "Browser - Conditional Organization", - "userSetupAllowed" : false - } ] - }, { - "id" : "b99c3a7a-8ef7-46b1-b8a1-cb51f8a6e725", - "alias" : "Reset - Conditional OTP", - "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "reset-otp", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "a3bfc2e4-af67-4d3e-851f-3c58bf32be83", - "alias" : "User creation or linking", - "description" : "Flow for the existing/non-existing user alternatives", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticatorConfig" : "create unique user config", - "authenticator" : "idp-create-user-if-unique", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "ALTERNATIVE", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "Handle Existing Account", - "userSetupAllowed" : false - } ] - }, { - "id" : "4cc3bf25-d1b7-43a6-8619-5ed5f2d65aed", - "alias" : "Verify Existing Account by Re-authentication", - "description" : "Reauthentication of existing account", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "idp-username-password-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "First broker login - Conditional OTP", - "userSetupAllowed" : false - } ] - }, { - "id" : "4e5564ce-87da-4b25-8dcb-062216ceaa8d", - "alias" : "browser", - "description" : "Browser based authentication", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "auth-cookie", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "auth-spnego", - "authenticatorFlow" : false, - "requirement" : "DISABLED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "identity-provider-redirector", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 25, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "ALTERNATIVE", - "priority" : 26, - "autheticatorFlow" : true, - "flowAlias" : "Organization", - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "ALTERNATIVE", - "priority" : 30, - "autheticatorFlow" : true, - "flowAlias" : "forms", - "userSetupAllowed" : false - } ] - }, { - "id" : "def90462-5831-4856-b186-05df9e640bbb", - "alias" : "clients", - "description" : "Base authentication for clients", - "providerId" : "client-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "client-secret", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "client-jwt", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "client-secret-jwt", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 30, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "client-x509", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 40, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "f8c9010d-f197-417b-bda1-2993e1a73a21", - "alias" : "direct grant", - "description" : "OpenID Connect Resource Owner Grant", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "direct-grant-validate-username", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "direct-grant-validate-password", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 30, - "autheticatorFlow" : true, - "flowAlias" : "Direct Grant - Conditional OTP", - "userSetupAllowed" : false - } ] - }, { - "id" : "0fb9e2a4-ea0d-453f-a1fe-f000c849fd66", - "alias" : "docker auth", - "description" : "Used by Docker clients to authenticate against the IDP", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "docker-http-basic-authenticator", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "79a9efc4-1279-4093-8914-92f4e0b02bb4", - "alias" : "first broker login", - "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticatorConfig" : "review profile config", - "authenticator" : "idp-review-profile", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "User creation or linking", - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 50, - "autheticatorFlow" : true, - "flowAlias" : "First Broker Login - Conditional Organization", - "userSetupAllowed" : false - } ] - }, { - "id" : "f855b3a1-6612-4528-94bc-d0793bfda561", - "alias" : "forms", - "description" : "Username, password, otp and other auth forms.", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "auth-username-password-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "Browser - Conditional OTP", - "userSetupAllowed" : false - } ] - }, { - "id" : "fb84970b-6f04-4849-a385-792e17c1b8ce", - "alias" : "registration", - "description" : "Registration flow", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "registration-page-form", - "authenticatorFlow" : true, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : true, - "flowAlias" : "registration form", - "userSetupAllowed" : false - } ] - }, { - "id" : "fcdfd4d4-1c04-487d-aa7c-85e136814274", - "alias" : "registration form", - "description" : "Registration form", - "providerId" : "form-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "registration-user-creation", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "registration-password-action", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 50, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "registration-recaptcha-action", - "authenticatorFlow" : false, - "requirement" : "DISABLED", - "priority" : 60, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "registration-terms-and-conditions", - "authenticatorFlow" : false, - "requirement" : "DISABLED", - "priority" : 70, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "306d8f7d-c12a-46cb-9a68-c6c3f1622f57", - "alias" : "reset credentials", - "description" : "Reset credentials for a user if they forgot their password or something", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "reset-credentials-choose-user", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "reset-credential-email", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "reset-password", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 30, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 40, - "autheticatorFlow" : true, - "flowAlias" : "Reset - Conditional OTP", - "userSetupAllowed" : false - } ] - }, { - "id" : "35a54b09-ff8c-46c4-9f04-1efbb153276c", - "alias" : "saml ecp", - "description" : "SAML ECP Profile Authentication Flow", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "http-basic-authenticator", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - } ], - "authenticatorConfig" : [ { - "id" : "fc1b82d7-593d-4906-a4d9-13220b66b7ce", - "alias" : "create unique user config", - "config" : { - "require.password.update.after.registration" : "false" - } - }, { - "id" : "a90543f4-7da7-43bc-8737-7e58dd190014", - "alias" : "review profile config", - "config" : { - "update.profile.on.first.login" : "missing" - } - } ], - "requiredActions" : [ { - "alias" : "CONFIGURE_TOTP", - "name" : "Configure OTP", - "providerId" : "CONFIGURE_TOTP", - "enabled" : true, - "defaultAction" : false, - "priority" : 10, - "config" : { } - }, { - "alias" : "TERMS_AND_CONDITIONS", - "name" : "Terms and Conditions", - "providerId" : "TERMS_AND_CONDITIONS", - "enabled" : false, - "defaultAction" : false, - "priority" : 20, - "config" : { } - }, { - "alias" : "UPDATE_PASSWORD", - "name" : "Update Password", - "providerId" : "UPDATE_PASSWORD", - "enabled" : true, - "defaultAction" : false, - "priority" : 30, - "config" : { } - }, { - "alias" : "UPDATE_PROFILE", - "name" : "Update Profile", - "providerId" : "UPDATE_PROFILE", - "enabled" : true, - "defaultAction" : false, - "priority" : 40, - "config" : { } - }, { - "alias" : "VERIFY_EMAIL", - "name" : "Verify Email", - "providerId" : "VERIFY_EMAIL", - "enabled" : true, - "defaultAction" : false, - "priority" : 50, - "config" : { } - }, { - "alias" : "delete_account", - "name" : "Delete Account", - "providerId" : "delete_account", - "enabled" : false, - "defaultAction" : false, - "priority" : 60, - "config" : { } - }, { - "alias" : "webauthn-register", - "name" : "Webauthn Register", - "providerId" : "webauthn-register", - "enabled" : true, - "defaultAction" : false, - "priority" : 70, - "config" : { } - }, { - "alias" : "webauthn-register-passwordless", - "name" : "Webauthn Register Passwordless", - "providerId" : "webauthn-register-passwordless", - "enabled" : true, - "defaultAction" : false, - "priority" : 80, - "config" : { } - }, { - "alias" : "VERIFY_PROFILE", - "name" : "Verify Profile", - "providerId" : "VERIFY_PROFILE", - "enabled" : true, - "defaultAction" : false, - "priority" : 90, - "config" : { } - }, { - "alias" : "delete_credential", - "name" : "Delete Credential", - "providerId" : "delete_credential", - "enabled" : true, - "defaultAction" : false, - "priority" : 100, - "config" : { } - }, { - "alias" : "update_user_locale", - "name" : "Update User Locale", - "providerId" : "update_user_locale", - "enabled" : true, - "defaultAction" : false, - "priority" : 1000, - "config" : { } - } ], - "browserFlow" : "browser", - "registrationFlow" : "registration", - "directGrantFlow" : "direct grant", - "resetCredentialsFlow" : "reset credentials", - "clientAuthenticationFlow" : "clients", - "dockerAuthenticationFlow" : "docker auth", - "firstBrokerLoginFlow" : "first broker login", - "attributes" : { - "cibaBackchannelTokenDeliveryMode" : "poll", - "cibaExpiresIn" : "120", - "cibaAuthRequestedUserHint" : "login_hint", - "oauth2DeviceCodeLifespan" : "600", - "oauth2DevicePollingInterval" : "5", - "parRequestUriLifespan" : "60", - "cibaInterval" : "5", - "realmReusableOtpCode" : "false" - }, - "keycloakVersion" : "26.1.3", - "userManagedAccessAllowed" : false, - "organizationsEnabled" : false, - "verifiableCredentialsEnabled" : false, - "adminPermissionsEnabled" : false, - "clientProfiles" : { - "profiles" : [ ] - }, - "clientPolicies" : { - "policies" : [ ] - } } diff --git a/idp/teacher-realm.json b/idp/teacher-realm.json index f1bc513a..fd965e96 100644 --- a/idp/teacher-realm.json +++ b/idp/teacher-realm.json @@ -1,2060 +1,2345 @@ { - "id" : "02ba6887-22f5-4de4-ad9b-cb2a2060bce1", - "realm" : "teacher", - "notBefore" : 0, - "defaultSignatureAlgorithm" : "RS256", - "revokeRefreshToken" : false, - "refreshTokenMaxReuse" : 0, - "accessTokenLifespan" : 300, - "accessTokenLifespanForImplicitFlow" : 900, - "ssoSessionIdleTimeout" : 1800, - "ssoSessionMaxLifespan" : 36000, - "ssoSessionIdleTimeoutRememberMe" : 0, - "ssoSessionMaxLifespanRememberMe" : 0, - "offlineSessionIdleTimeout" : 2592000, - "offlineSessionMaxLifespanEnabled" : false, - "offlineSessionMaxLifespan" : 5184000, - "clientSessionIdleTimeout" : 0, - "clientSessionMaxLifespan" : 0, - "clientOfflineSessionIdleTimeout" : 0, - "clientOfflineSessionMaxLifespan" : 0, - "accessCodeLifespan" : 60, - "accessCodeLifespanUserAction" : 300, - "accessCodeLifespanLogin" : 1800, - "actionTokenGeneratedByAdminLifespan" : 43200, - "actionTokenGeneratedByUserLifespan" : 300, - "oauth2DeviceCodeLifespan" : 600, - "oauth2DevicePollingInterval" : 5, - "enabled" : true, - "sslRequired" : "external", - "registrationAllowed" : false, - "registrationEmailAsUsername" : false, - "rememberMe" : false, - "verifyEmail" : false, - "loginWithEmailAllowed" : true, - "duplicateEmailsAllowed" : false, - "resetPasswordAllowed" : false, - "editUsernameAllowed" : false, - "bruteForceProtected" : false, - "permanentLockout" : false, - "maxTemporaryLockouts" : 0, - "bruteForceStrategy" : "MULTIPLE", - "maxFailureWaitSeconds" : 900, - "minimumQuickLoginWaitSeconds" : 60, - "waitIncrementSeconds" : 60, - "quickLoginCheckMilliSeconds" : 1000, - "maxDeltaTimeSeconds" : 43200, - "failureFactor" : 30, - "roles" : { - "realm" : [ { - "id" : "e7f1e366-0bfc-4469-bcde-92bcd1ed5ce7", - "name" : "uma_authorization", - "description" : "${role_uma_authorization}", - "composite" : false, - "clientRole" : false, - "containerId" : "02ba6887-22f5-4de4-ad9b-cb2a2060bce1", - "attributes" : { } - }, { - "id" : "6b546a34-4ebe-4c09-b274-fc1f6bebdf93", - "name" : "default-roles-teacher", - "description" : "${role_default-roles}", - "composite" : true, - "composites" : { - "realm" : [ "offline_access", "uma_authorization" ], - "client" : { - "account" : [ "manage-account", "view-profile" ] + "id": "02ba6887-22f5-4de4-ad9b-cb2a2060bce1", + "realm": "teacher", + "notBefore": 0, + "defaultSignatureAlgorithm": "RS256", + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 300, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "ssoSessionIdleTimeoutRememberMe": 0, + "ssoSessionMaxLifespanRememberMe": 0, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": false, + "offlineSessionMaxLifespan": 5184000, + "clientSessionIdleTimeout": 0, + "clientSessionMaxLifespan": 0, + "clientOfflineSessionIdleTimeout": 0, + "clientOfflineSessionMaxLifespan": 0, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "accessCodeLifespanLogin": 1800, + "actionTokenGeneratedByAdminLifespan": 43200, + "actionTokenGeneratedByUserLifespan": 300, + "oauth2DeviceCodeLifespan": 600, + "oauth2DevicePollingInterval": 5, + "enabled": true, + "sslRequired": "external", + "registrationAllowed": false, + "registrationEmailAsUsername": false, + "rememberMe": false, + "verifyEmail": false, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": false, + "editUsernameAllowed": false, + "bruteForceProtected": false, + "permanentLockout": false, + "maxTemporaryLockouts": 0, + "bruteForceStrategy": "MULTIPLE", + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 30, + "roles": { + "realm": [ + { + "id": "e7f1e366-0bfc-4469-bcde-92bcd1ed5ce7", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "composite": false, + "clientRole": false, + "containerId": "02ba6887-22f5-4de4-ad9b-cb2a2060bce1", + "attributes": {} + }, + { + "id": "6b546a34-4ebe-4c09-b274-fc1f6bebdf93", + "name": "default-roles-teacher", + "description": "${role_default-roles}", + "composite": true, + "composites": { + "realm": ["offline_access", "uma_authorization"], + "client": { + "account": ["manage-account", "view-profile"] + } + }, + "clientRole": false, + "containerId": "02ba6887-22f5-4de4-ad9b-cb2a2060bce1", + "attributes": {} + }, + { + "id": "747c4433-f128-4f72-b56f-315e7779d4fd", + "name": "offline_access", + "description": "${role_offline-access}", + "composite": false, + "clientRole": false, + "containerId": "02ba6887-22f5-4de4-ad9b-cb2a2060bce1", + "attributes": {} + } + ], + "client": { + "realm-management": [ + { + "id": "4c8243b1-b576-4cb2-a4f7-3ce25e408fe5", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes": {} + }, + { + "id": "71fd672b-024b-4d44-b058-03320aeb1842", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "realm-management": ["query-groups", "query-users"] + } + }, + "clientRole": true, + "containerId": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes": {} + }, + { + "id": "fea88d42-3065-4600-a5b6-c4e2589e1304", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes": {} + }, + { + "id": "6247b5b0-4d41-4fda-900c-3dfc725e03a2", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes": {} + }, + { + "id": "a3b55a4b-b7f9-4db3-a64f-6ddf80bf74e7", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes": {} + }, + { + "id": "d6714bc8-ff2d-4da0-98b4-2a6479e67954", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes": {} + }, + { + "id": "d389da82-1730-4c66-9b43-34ac3c8d7f6c", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes": {} + }, + { + "id": "4dc3905f-311b-4de0-b2e6-a3de50a078a3", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes": {} + }, + { + "id": "28ea5d84-4e7d-484e-82fa-c9adcea4ffc0", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes": {} + }, + { + "id": "e020bc9c-f2c9-4023-82eb-b62266749334", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes": {} + }, + { + "id": "e7373af5-924a-4f01-b34d-55a09aac6c74", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes": {} + }, + { + "id": "0879b6d5-7db6-4c83-8b99-e889028cb13e", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes": {} + }, + { + "id": "ff2c82f3-7f04-4ced-9127-65097e2c16b9", + "name": "realm-admin", + "description": "${role_realm-admin}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "impersonation", + "view-users", + "view-events", + "manage-users", + "view-authorization", + "query-users", + "query-realms", + "manage-events", + "manage-identity-providers", + "query-clients", + "manage-realm", + "view-clients", + "manage-clients", + "query-groups", + "create-client", + "view-realm", + "manage-authorization", + "view-identity-providers" + ] + } + }, + "clientRole": true, + "containerId": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes": {} + }, + { + "id": "156a28de-00d8-4828-9dc9-e09e7841312f", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "realm-management": ["query-clients"] + } + }, + "clientRole": true, + "containerId": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes": {} + }, + { + "id": "a241d7dd-b028-474a-bdf8-4d33e00c1b90", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes": {} + }, + { + "id": "681e3f7e-bb8c-4e09-a49e-ba8c21f916ff", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes": {} + }, + { + "id": "1c5886ad-b354-4246-b288-13ea7635db58", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes": {} + }, + { + "id": "7dedf6ff-b715-4f14-85ac-40d0652f153d", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes": {} + }, + { + "id": "694721e8-3bf3-47b5-ae38-874db0dc7740", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "attributes": {} + } + ], + "dwengo": [], + "security-admin-console": [], + "admin-cli": [], + "account-console": [], + "broker": [ + { + "id": "0cb1b2b5-a751-4f09-ac2f-ea26c398a857", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "cfd0202e-a6b9-4c5e-9f49-2ef17df9089b", + "attributes": {} + } + ], + "account": [ + { + "id": "d21c51c5-353c-4d78-8c8d-8b8e9f37efa8", + "name": "manage-account-links", + "description": "${role_manage-account-links}", + "composite": false, + "clientRole": true, + "containerId": "7ceb65eb-30da-4dc3-95bc-f06863362fd6", + "attributes": {} + }, + { + "id": "49c8ac02-defa-41af-9e63-2fd24cfc103f", + "name": "view-groups", + "description": "${role_view-groups}", + "composite": false, + "clientRole": true, + "containerId": "7ceb65eb-30da-4dc3-95bc-f06863362fd6", + "attributes": {} + }, + { + "id": "3850c5cc-510a-417b-9976-a1d1d6650804", + "name": "manage-account", + "description": "${role_manage-account}", + "composite": true, + "composites": { + "client": { + "account": ["manage-account-links"] + } + }, + "clientRole": true, + "containerId": "7ceb65eb-30da-4dc3-95bc-f06863362fd6", + "attributes": {} + }, + { + "id": "6554709e-304a-428f-8665-970aacd1dae8", + "name": "view-consent", + "description": "${role_view-consent}", + "composite": false, + "clientRole": true, + "containerId": "7ceb65eb-30da-4dc3-95bc-f06863362fd6", + "attributes": {} + }, + { + "id": "7a0c9d85-daea-4b80-93b5-095e21e5d569", + "name": "delete-account", + "description": "${role_delete-account}", + "composite": false, + "clientRole": true, + "containerId": "7ceb65eb-30da-4dc3-95bc-f06863362fd6", + "attributes": {} + }, + { + "id": "ee2c5cff-1b05-417f-ab3a-a796be754299", + "name": "manage-consent", + "description": "${role_manage-consent}", + "composite": true, + "composites": { + "client": { + "account": ["view-consent"] + } + }, + "clientRole": true, + "containerId": "7ceb65eb-30da-4dc3-95bc-f06863362fd6", + "attributes": {} + }, + { + "id": "128fb31d-0784-4b4e-9aa5-82ceb2824fa0", + "name": "view-profile", + "description": "${role_view-profile}", + "composite": false, + "clientRole": true, + "containerId": "7ceb65eb-30da-4dc3-95bc-f06863362fd6", + "attributes": {} + }, + { + "id": "ca850b8d-b75b-4b04-9e42-1e4cc8ab2179", + "name": "view-applications", + "description": "${role_view-applications}", + "composite": false, + "clientRole": true, + "containerId": "7ceb65eb-30da-4dc3-95bc-f06863362fd6", + "attributes": {} + } + ] } - }, - "clientRole" : false, - "containerId" : "02ba6887-22f5-4de4-ad9b-cb2a2060bce1", - "attributes" : { } - }, { - "id" : "747c4433-f128-4f72-b56f-315e7779d4fd", - "name" : "offline_access", - "description" : "${role_offline-access}", - "composite" : false, - "clientRole" : false, - "containerId" : "02ba6887-22f5-4de4-ad9b-cb2a2060bce1", - "attributes" : { } - } ], - "client" : { - "realm-management" : [ { - "id" : "4c8243b1-b576-4cb2-a4f7-3ce25e408fe5", - "name" : "impersonation", - "description" : "${role_impersonation}", - "composite" : false, - "clientRole" : true, - "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "attributes" : { } - }, { - "id" : "71fd672b-024b-4d44-b058-03320aeb1842", - "name" : "view-users", - "description" : "${role_view-users}", - "composite" : true, - "composites" : { - "client" : { - "realm-management" : [ "query-groups", "query-users" ] - } + }, + "groups": [], + "defaultRole": { + "id": "6b546a34-4ebe-4c09-b274-fc1f6bebdf93", + "name": "default-roles-teacher", + "description": "${role_default-roles}", + "composite": true, + "clientRole": false, + "containerId": "02ba6887-22f5-4de4-ad9b-cb2a2060bce1" + }, + "requiredCredentials": ["password"], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpPolicyCodeReusable": false, + "otpSupportedApplications": ["totpAppFreeOTPName", "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName"], + "localizationTexts": {}, + "webAuthnPolicyRpEntityName": "keycloak", + "webAuthnPolicySignatureAlgorithms": ["ES256", "RS256"], + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "webAuthnPolicyCreateTimeout": 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyAcceptableAaguids": [], + "webAuthnPolicyExtraOrigins": [], + "webAuthnPolicyPasswordlessRpEntityName": "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms": ["ES256", "RS256"], + "webAuthnPolicyPasswordlessRpId": "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", + "webAuthnPolicyPasswordlessCreateTimeout": 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyPasswordlessAcceptableAaguids": [], + "webAuthnPolicyPasswordlessExtraOrigins": [], + "users": [ + { + "id": "63dbbb64-c09f-4e4e-9cbf-af9e557dbb09", + "username": "testleerkracht1", + "firstName": "Kris", + "lastName": "Coolsaet", + "email": "kris.coolsaet@ugent.be", + "emailVerified": false, + "createdTimestamp": 1740866530658, + "enabled": true, + "totp": false, + "credentials": [ + { + "id": "c5382bf7-ccc6-47de-93b9-2c11ea7b6862", + "type": "password", + "userLabel": "My password", + "createdDate": 1740866544032, + "secretData": "{\"value\":\"H2vKyHF3j/alz6CNap2uaKSRb+/wrWImVecj7dcHe1w=\",\"salt\":\"32WjW1KzFaR5RJqU0Pfq9w==\",\"additionalParameters\":{}}", + "credentialData": "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}" + } + ], + "disableableCredentialTypes": [], + "requiredActions": [], + "realmRoles": ["default-roles-teacher"], + "notBefore": 0, + "groups": [] + } + ], + "scopeMappings": [ + { + "clientScope": "offline_access", + "roles": ["offline_access"] + } + ], + "clientScopeMappings": { + "account": [ + { + "client": "account-console", + "roles": ["manage-account", "view-groups"] + } + ] + }, + "clients": [ + { + "id": "7ceb65eb-30da-4dc3-95bc-f06863362fd6", + "clientId": "account", + "name": "${client_account}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/teacher/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": ["/realms/teacher/account/*"], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": ["web-origins", "acr", "roles", "profile", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, - "clientRole" : true, - "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "attributes" : { } - }, { - "id" : "fea88d42-3065-4600-a5b6-c4e2589e1304", - "name" : "view-events", - "description" : "${role_view-events}", - "composite" : false, - "clientRole" : true, - "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "attributes" : { } - }, { - "id" : "6247b5b0-4d41-4fda-900c-3dfc725e03a2", - "name" : "manage-users", - "description" : "${role_manage-users}", - "composite" : false, - "clientRole" : true, - "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "attributes" : { } - }, { - "id" : "a3b55a4b-b7f9-4db3-a64f-6ddf80bf74e7", - "name" : "view-authorization", - "description" : "${role_view-authorization}", - "composite" : false, - "clientRole" : true, - "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "attributes" : { } - }, { - "id" : "d6714bc8-ff2d-4da0-98b4-2a6479e67954", - "name" : "manage-events", - "description" : "${role_manage-events}", - "composite" : false, - "clientRole" : true, - "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "attributes" : { } - }, { - "id" : "d389da82-1730-4c66-9b43-34ac3c8d7f6c", - "name" : "query-realms", - "description" : "${role_query-realms}", - "composite" : false, - "clientRole" : true, - "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "attributes" : { } - }, { - "id" : "4dc3905f-311b-4de0-b2e6-a3de50a078a3", - "name" : "query-users", - "description" : "${role_query-users}", - "composite" : false, - "clientRole" : true, - "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "attributes" : { } - }, { - "id" : "28ea5d84-4e7d-484e-82fa-c9adcea4ffc0", - "name" : "manage-identity-providers", - "description" : "${role_manage-identity-providers}", - "composite" : false, - "clientRole" : true, - "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "attributes" : { } - }, { - "id" : "e020bc9c-f2c9-4023-82eb-b62266749334", - "name" : "query-clients", - "description" : "${role_query-clients}", - "composite" : false, - "clientRole" : true, - "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "attributes" : { } - }, { - "id" : "e7373af5-924a-4f01-b34d-55a09aac6c74", - "name" : "manage-clients", - "description" : "${role_manage-clients}", - "composite" : false, - "clientRole" : true, - "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "attributes" : { } - }, { - "id" : "0879b6d5-7db6-4c83-8b99-e889028cb13e", - "name" : "manage-realm", - "description" : "${role_manage-realm}", - "composite" : false, - "clientRole" : true, - "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "attributes" : { } - }, { - "id" : "ff2c82f3-7f04-4ced-9127-65097e2c16b9", - "name" : "realm-admin", - "description" : "${role_realm-admin}", - "composite" : true, - "composites" : { - "client" : { - "realm-management" : [ "impersonation", "view-users", "view-events", "manage-users", "view-authorization", "query-users", "query-realms", "manage-events", "manage-identity-providers", "query-clients", "manage-realm", "view-clients", "manage-clients", "query-groups", "create-client", "view-realm", "manage-authorization", "view-identity-providers" ] - } + { + "id": "920e8621-36b5-4046-b1cd-4b293668f64b", + "clientId": "account-console", + "name": "${client_account-console}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/teacher/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": ["/realms/teacher/account/*"], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "cd3f4ae0-3008-488b-88c5-b6d640a9edd3", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": ["web-origins", "acr", "roles", "profile", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, - "clientRole" : true, - "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "attributes" : { } - }, { - "id" : "156a28de-00d8-4828-9dc9-e09e7841312f", - "name" : "view-clients", - "description" : "${role_view-clients}", - "composite" : true, - "composites" : { - "client" : { - "realm-management" : [ "query-clients" ] - } + { + "id": "9d7b2827-b7bb-451e-ad38-8f55a69f7c9c", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "client.use.lightweight.access.token.enabled": "true" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": ["web-origins", "acr", "roles", "profile", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, - "clientRole" : true, - "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "attributes" : { } - }, { - "id" : "a241d7dd-b028-474a-bdf8-4d33e00c1b90", - "name" : "create-client", - "description" : "${role_create-client}", - "composite" : false, - "clientRole" : true, - "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "attributes" : { } - }, { - "id" : "681e3f7e-bb8c-4e09-a49e-ba8c21f916ff", - "name" : "query-groups", - "description" : "${role_query-groups}", - "composite" : false, - "clientRole" : true, - "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "attributes" : { } - }, { - "id" : "1c5886ad-b354-4246-b288-13ea7635db58", - "name" : "view-realm", - "description" : "${role_view-realm}", - "composite" : false, - "clientRole" : true, - "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "attributes" : { } - }, { - "id" : "7dedf6ff-b715-4f14-85ac-40d0652f153d", - "name" : "manage-authorization", - "description" : "${role_manage-authorization}", - "composite" : false, - "clientRole" : true, - "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "attributes" : { } - }, { - "id" : "694721e8-3bf3-47b5-ae38-874db0dc7740", - "name" : "view-identity-providers", - "description" : "${role_view-identity-providers}", - "composite" : false, - "clientRole" : true, - "containerId" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "attributes" : { } - } ], - "dwengo" : [ ], - "security-admin-console" : [ ], - "admin-cli" : [ ], - "account-console" : [ ], - "broker" : [ { - "id" : "0cb1b2b5-a751-4f09-ac2f-ea26c398a857", - "name" : "read-token", - "description" : "${role_read-token}", - "composite" : false, - "clientRole" : true, - "containerId" : "cfd0202e-a6b9-4c5e-9f49-2ef17df9089b", - "attributes" : { } - } ], - "account" : [ { - "id" : "d21c51c5-353c-4d78-8c8d-8b8e9f37efa8", - "name" : "manage-account-links", - "description" : "${role_manage-account-links}", - "composite" : false, - "clientRole" : true, - "containerId" : "7ceb65eb-30da-4dc3-95bc-f06863362fd6", - "attributes" : { } - }, { - "id" : "49c8ac02-defa-41af-9e63-2fd24cfc103f", - "name" : "view-groups", - "description" : "${role_view-groups}", - "composite" : false, - "clientRole" : true, - "containerId" : "7ceb65eb-30da-4dc3-95bc-f06863362fd6", - "attributes" : { } - }, { - "id" : "3850c5cc-510a-417b-9976-a1d1d6650804", - "name" : "manage-account", - "description" : "${role_manage-account}", - "composite" : true, - "composites" : { - "client" : { - "account" : [ "manage-account-links" ] - } + { + "id": "cfd0202e-a6b9-4c5e-9f49-2ef17df9089b", + "clientId": "broker", + "name": "${client_broker}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "true" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": ["web-origins", "acr", "roles", "profile", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, - "clientRole" : true, - "containerId" : "7ceb65eb-30da-4dc3-95bc-f06863362fd6", - "attributes" : { } - }, { - "id" : "6554709e-304a-428f-8665-970aacd1dae8", - "name" : "view-consent", - "description" : "${role_view-consent}", - "composite" : false, - "clientRole" : true, - "containerId" : "7ceb65eb-30da-4dc3-95bc-f06863362fd6", - "attributes" : { } - }, { - "id" : "7a0c9d85-daea-4b80-93b5-095e21e5d569", - "name" : "delete-account", - "description" : "${role_delete-account}", - "composite" : false, - "clientRole" : true, - "containerId" : "7ceb65eb-30da-4dc3-95bc-f06863362fd6", - "attributes" : { } - }, { - "id" : "ee2c5cff-1b05-417f-ab3a-a796be754299", - "name" : "manage-consent", - "description" : "${role_manage-consent}", - "composite" : true, - "composites" : { - "client" : { - "account" : [ "view-consent" ] - } + { + "id": "abdee18a-4549-48b5-b976-4c1a42820ef9", + "clientId": "dwengo", + "name": "Dwengo", + "description": "", + "rootUrl": "http://localhost:5173", + "adminUrl": "http://localhost:5173", + "baseUrl": "http://localhost:5173", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": ["urn:ietf:wg:oauth:2.0:oob", "http://localhost:5173/*", "http://localhost:5173"], + "webOrigins": ["+"], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": true, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": true, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "oidc.ciba.grant.enabled": "false", + "backchannel.logout.session.required": "true", + "post.logout.redirect.uris": "+", + "frontchannel.logout.session.required": "true", + "oauth2.device.authorization.grant.enabled": "false", + "display.on.consent.screen": "false", + "backchannel.logout.revoke.offline.tokens": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": ["web-origins", "acr", "roles", "profile", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, - "clientRole" : true, - "containerId" : "7ceb65eb-30da-4dc3-95bc-f06863362fd6", - "attributes" : { } - }, { - "id" : "128fb31d-0784-4b4e-9aa5-82ceb2824fa0", - "name" : "view-profile", - "description" : "${role_view-profile}", - "composite" : false, - "clientRole" : true, - "containerId" : "7ceb65eb-30da-4dc3-95bc-f06863362fd6", - "attributes" : { } - }, { - "id" : "ca850b8d-b75b-4b04-9e42-1e4cc8ab2179", - "name" : "view-applications", - "description" : "${role_view-applications}", - "composite" : false, - "clientRole" : true, - "containerId" : "7ceb65eb-30da-4dc3-95bc-f06863362fd6", - "attributes" : { } - } ] + { + "id": "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", + "clientId": "realm-management", + "name": "${client_realm-management}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "true" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": ["web-origins", "acr", "roles", "profile", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] + }, + { + "id": "c421853c-5bdf-4ea9-ae97-51f5ad7b8df8", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "rootUrl": "${authAdminUrl}", + "baseUrl": "/admin/teacher/console/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": ["/admin/teacher/console/*"], + "webOrigins": ["+"], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "client.use.lightweight.access.token.enabled": "true", + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "a9a893af-925e-46c9-ba33-47b06101ce5f", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": ["web-origins", "acr", "roles", "profile", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] + } + ], + "clientScopes": [ + { + "id": "fef4fbeb-d7e6-4474-b802-6c63df0dc9a3", + "name": "saml_organization", + "description": "Organization Membership", + "protocol": "saml", + "attributes": { + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "2384b79b-5cc3-4e1c-b4b2-4bee2ceeed72", + "name": "organization", + "protocol": "saml", + "protocolMapper": "saml-organization-membership-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "a097893c-7eed-4556-b2ed-3751c7fc3c51", + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + }, + { + "id": "ffc38cb2-eb10-47cf-a2d6-6647fdd4da65", + "name": "service_account", + "description": "Specific scope for a client enabled for service accounts", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "06ed3629-1c3d-48d9-80c6-98fcd3958c48", + "name": "Client Host", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientHost", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientHost", + "jsonType.label": "String" + } + }, + { + "id": "04eeb81e-05c0-484a-91df-9a79138bcd66", + "name": "Client IP Address", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientAddress", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientAddress", + "jsonType.label": "String" + } + }, + { + "id": "6e673f49-ce38-4583-8040-8a2e7ec5e7c8", + "name": "Client ID", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "client_id", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "client_id", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "ee188d9c-ab26-4e53-a16c-c9f77094f854", + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${profileScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "05ff270b-6a50-4bbb-903d-9546a59f20bf", + "name": "picture", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "picture", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "picture", + "jsonType.label": "String" + } + }, + { + "id": "394f808d-bc7b-476e-a372-7cfece5c6db0", + "name": "gender", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "gender", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "gender", + "jsonType.label": "String" + } + }, + { + "id": "0371c44f-c6e0-4f88-ac8f-17a56e2b90f8", + "name": "profile", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "profile", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "profile", + "jsonType.label": "String" + } + }, + { + "id": "21d66073-42f2-443b-aac4-e49c9038253c", + "name": "birthdate", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "birthdate", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "birthdate", + "jsonType.label": "String" + } + }, + { + "id": "5cc6a97f-9d1a-4c72-b682-af6d1bd36883", + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "id": "d6a6d46b-80a7-4228-af07-0faae2911fed", + "name": "nickname", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "nickname", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "nickname", + "jsonType.label": "String" + } + }, + { + "id": "322b508a-7464-4b0f-90df-3f489975a62e", + "name": "zoneinfo", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "zoneinfo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "zoneinfo", + "jsonType.label": "String" + } + }, + { + "id": "f757ae7a-3005-4899-bb4e-da1ab4b47bb0", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + }, + { + "id": "bab8eb17-0cb0-4275-8456-aa1d65933a35", + "name": "updated at", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "updatedAt", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "updated_at", + "jsonType.label": "long" + } + }, + { + "id": "6ea1d43c-d4c7-4f2f-93b0-dfdb3bb584eb", + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "given_name", + "jsonType.label": "String" + } + }, + { + "id": "3a2ebc93-05fb-4904-996b-5e3331b72fcd", + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "family_name", + "jsonType.label": "String" + } + }, + { + "id": "217b417e-d4f6-4225-bf92-3bd38f6fbefb", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String" + } + }, + { + "id": "3dd5da51-5842-4358-a69f-f7ffffe521ac", + "name": "website", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "website", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "website", + "jsonType.label": "String" + } + }, + { + "id": "790bda99-1c27-4970-b3b9-4fa1c90c738c", + "name": "middle name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "middleName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "middle_name", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "e6cf59c7-9390-4f48-ab01-79a0fa138960", + "name": "organization", + "description": "Additional claims about the organization a subject belongs to", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${organizationScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "417ff129-6b95-4e95-9f57-a6699ca18d8d", + "name": "organization", + "protocol": "openid-connect", + "protocolMapper": "oidc-organization-membership-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "organization", + "jsonType.label": "String", + "multivalued": "true" + } + } + ] + }, + { + "id": "43d92ef5-76d8-4df0-84b5-5f833875d345", + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${emailScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "74d21718-190a-4c53-b446-b07e5f029394", + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + }, + { + "id": "949871a0-d68c-4563-a9b3-945a3148f937", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "b07a2014-d07e-450f-a593-66e9f9cf4799", + "name": "acr", + "description": "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "79efdc37-0f06-43e6-a516-7bc9dc29f04d", + "name": "acr loa level", + "protocol": "openid-connect", + "protocolMapper": "oidc-acr-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "id": "3bbbff21-0446-4813-8bdf-54c35d8fffca", + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "0e996cda-fe5b-439d-ba4c-cf2129ae812f", + "name": "upn", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "upn", + "jsonType.label": "String" + } + }, + { + "id": "ddf1efe2-e765-475c-a4a0-d52f1f597834", + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "multivalued": "true", + "user.attribute": "foo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "93a40d0e-f163-42f7-a9d4-53cc2e17914e", + "name": "basic", + "description": "OpenID Connect scope for add all basic claims to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "41eb9e93-8e04-404b-a12b-40ef5a55f640", + "name": "sub", + "protocol": "openid-connect", + "protocolMapper": "oidc-sub-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + }, + { + "id": "1291062a-10f6-4061-b9ea-f54ff5d8ec54", + "name": "auth_time", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "AUTH_TIME", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "auth_time", + "jsonType.label": "long" + } + } + ] + }, + { + "id": "9ea27173-e54b-42f0-8f6c-5a36c5073ede", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "d10a6975-8aeb-4215-8d6b-23b0286d4abb", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "e8a99a5a-1519-4c7d-a3f0-ac6d34c61a0b", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${phoneScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "b2de087f-169f-44b3-ad46-3a063ac9025f", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", + "jsonType.label": "String" + } + }, + { + "id": "ffb8aebd-0d03-4811-8fd4-aa03bda36b2d", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "phoneNumberVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "30e06d84-f610-4f17-8820-6f785a510357", + "name": "address", + "description": "OpenID Connect built-in scope: address", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${addressScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "de707a09-a895-4b67-9ac5-0ff4e69715ea", + "name": "address", + "protocol": "openid-connect", + "protocolMapper": "oidc-address-mapper", + "consentRequired": false, + "config": { + "user.attribute.formatted": "formatted", + "user.attribute.country": "country", + "introspection.token.claim": "true", + "user.attribute.postal_code": "postal_code", + "userinfo.token.claim": "true", + "user.attribute.street": "street", + "id.token.claim": "true", + "user.attribute.region": "region", + "access.token.claim": "true", + "user.attribute.locality": "locality" + } + } + ] + }, + { + "id": "1762c903-9f07-451c-915d-855488e4aa42", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "consent.screen.text": "", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "0164bdc3-c79d-4467-b6bf-ca9a6889d04c", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "id": "91301d6d-0bb9-4da6-b8db-ee2480e25fee", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "consent.screen.text": "${rolesScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "2880d772-b0da-4ee8-bf1e-3f729a945db9", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "535042c5-58c5-4225-94b8-0b5b3411968e", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "a88432f1-565f-480d-958d-a5cea1dbcf0a", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + } + ], + "defaultDefaultClientScopes": ["role_list", "saml_organization", "profile", "email", "roles", "web-origins", "acr", "basic"], + "defaultOptionalClientScopes": ["offline_access", "address", "phone", "microprofile-jwt", "organization"], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "referrerPolicy": "no-referrer", + "xRobotsTag": "none", + "xFrameOptions": "SAMEORIGIN", + "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection": "1; mode=block", + "strictTransportSecurity": "max-age=31536000; includeSubDomains" + }, + "smtpServer": {}, + "eventsEnabled": false, + "eventsListeners": ["jboss-logging"], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "identityProviders": [], + "identityProviderMappers": [], + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "a689e06a-e440-4d94-ba54-692fba5a5486", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": ["200"] + } + }, + { + "id": "2778fda5-0a9f-40ab-ab4b-054ff8ce38e9", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": ["true"] + } + }, + { + "id": "36dc0167-9c9a-4b4a-9f04-29129aecac4d", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-sha256-pairwise-sub-mapper", + "oidc-usermodel-property-mapper", + "saml-user-attribute-mapper", + "oidc-full-name-mapper", + "saml-user-property-mapper", + "oidc-address-mapper", + "saml-role-list-mapper", + "oidc-usermodel-attribute-mapper" + ] + } + }, + { + "id": "4b79c6fd-5166-4bc2-ab0b-bff0018452f6", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "2003600a-89fb-421e-9dfe-d5096ee7fd4e", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-full-name-mapper", + "oidc-usermodel-attribute-mapper", + "oidc-address-mapper", + "oidc-sha256-pairwise-sub-mapper", + "saml-role-list-mapper", + "saml-user-property-mapper", + "saml-user-attribute-mapper", + "oidc-usermodel-property-mapper" + ] + } + }, + { + "id": "d62a2e93-f877-462a-bad3-93dcf91d49d2", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": ["true"], + "client-uris-must-match": ["true"] + } + }, + { + "id": "6e659a80-a638-4504-b507-21b9f77586ed", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "9ef67c59-5c3e-40cf-90ee-516b2e35ed3d", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": ["true"] + } + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "b5365a56-e00d-4612-80bf-262a9c8dba7c", + "name": "rsa-enc-generated", + "providerId": "rsa-enc-generated", + "subComponents": {}, + "config": { + "privateKey": [ + "MIIEogIBAAKCAQEAudnbEbQij+g9JWYMuyJjF/sKe4fVEd9SrCmkFeAHZ7dEAmEKQcAlvJn1aL99pAm8KV0w9PAZugQx7ZzG6eUm4JLc+LYGJ8G8JDiVR6hIWRQ3k9HGcUwNacHKFlDj4XOeMykwLEo7jrQHAUx82vJO8bKZr2ixZqGc1UUUQNbEVYv0HzxhPKPoFYh9qQ8U6P0r/K9xIusLL6ZzmXx6uXqQuqtse05e5G9xwLjQDDrOKju4s1PJ1GZLt5Db9PGypMeA9J34tGL3O0rQom2WbO7R2GZGX044ZoNw6UnraGTmCxin1ywmwTq3JTb1IZ4DPLH/rucnPuKUb60B5ByPmXW/lQIDAQABAoIBAAlyYrGLbb9RX3xNa+O+O3m+U7nUPXcfWikwo6vN+6pgtScGzjnp3bEwxTnqE+WY7hTPLRwiMTiUmoIYuD6u3HNJW8yTmgv+y8SukJ34FpdakPmlTdg39K2VwWMxgOfWk+nHU/DIZC8chQeinu0VKICeIrQ5Ft1f5SQtEvq5v/iWIql+v2ipxdJ2dSl1NIO0/2S2Lyd7Slab50gbJ3kP0uZggN5IMtNd5GBvAbV+jaT4QWKuyXyHqOnyU/+2WU+XhmVPrX6c29sQg2CilqWf4RzEIeO/FgAiANEPyaAgW6mGtf17K1xsSrusyGMUsNGsGJSd7Q8K2o7g/Jv9V8160iECgYEA2xgKIoZ6+fT7UIDr+5insRr6PIht2WYl+JqibjzNRh+rvp1fjKkmjMOA39V6cvLaAHieSOUerSOD7nQONCedpHe6To1zOG9z5yYGgwa/2c/9eNORJq8vNw/4wXaARVf0mCNaexugPTdYvsSaqwW4+azIbB21xXUfKykLp0SjNfUCgYEA2ShJSZyTIqJ64IHi+Kj/E22ajK2DYBiFgNDmzKrW/ANO5ADumgMhahCcxW28Nw68n25vBWCK4o+6eVg1ldEdB1LxoKOYZAaA+zAiMsGI1/ndxdnlFopuJZguKhYDTmxzT0KcD9mApLKZBnCadGjG3FcdC8i14OK6S9lUIIpCvyECgYBXqWC0u7YMuPatGUhSXJwMAs1I1xWMvJBIziZbkTxY6GchV3pZn3xrKfYwmQvrXjvXoGtEo1gI0oMBL7JXL9qlabpDn9kQJZfsToygdFzi25OBerVDEykDEQLo9W8RT8Xv8YVMaJtOowyBF80CzMFcNMPkbmbCYMBd1ohxHsdm2QKBgGB9RhMvPzFkgLTBAdj7Plujl8hqULWiL6/NIsBOKLhRv/wPbfWA7pfySbZvy/Gq2qT8rNf2zb9dnb3NNAIdqIhYkoSOLGhFe4ohGRD0bZmJrMD80I3zdH2/4MNShKWUCqhtMGraeg60TMpPvlF7POEq0/0ocag7FgwdxQOwa3gBAoGASvjvVtfXyzWA9MycWLvlTPEGW5bjXrroYwulF8DkKfIaKWHfEiulTwQe4SHgS7CzWSg8KgvKIhJC/yTwfOtxZ894G9LWivwjjZCottIE+/qs6ioYSXouQr6IsWxs7U0i3gP36tsePjuSjR06kpBGfcFdynypAAq+mVBCV0Mxk9A=" + ], + "keyUse": ["ENC"], + "certificate": [ + "MIICnTCCAYUCBgGVU7avyzANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAd0ZWFjaGVyMB4XDTI1MDMwMTIxNTUzNloXDTM1MDMwMTIxNTcxNlowEjEQMA4GA1UEAwwHdGVhY2hlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALnZ2xG0Io/oPSVmDLsiYxf7CnuH1RHfUqwppBXgB2e3RAJhCkHAJbyZ9Wi/faQJvCldMPTwGboEMe2cxunlJuCS3Pi2BifBvCQ4lUeoSFkUN5PRxnFMDWnByhZQ4+FznjMpMCxKO460BwFMfNryTvGyma9osWahnNVFFEDWxFWL9B88YTyj6BWIfakPFOj9K/yvcSLrCy+mc5l8erl6kLqrbHtOXuRvccC40Aw6zio7uLNTydRmS7eQ2/TxsqTHgPSd+LRi9ztK0KJtlmzu0dhmRl9OOGaDcOlJ62hk5gsYp9csJsE6tyU29SGeAzyx/67nJz7ilG+tAeQcj5l1v5UCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAf3HTufrfWb0uqsEwfUETl4S4IbJOjqDdzFhUkMVtiq5I9LLUlJ7StZ6eoDCEoKUzF2lPy0qR2Om7IKC8BA7J5qUio0NSNh9j/t1Ipcjzx6SQI2cD6AjJFZndnF+OBTxdm9c6J+KMho6ZSMQEGwn2osgRBeItauxUshogQJPY/GzWMHlZyCAJcYtuflzgyw1VIQ0OiWCpCiSGeWpojxh19KR9qSBU1rETZMLokmdp84muq8aqEnNIFY5XRyUdH4gjNBx3TGsammZbvzuZdZIDvFNE19SXl/J9QcWJlRw0DuOblLcLKiamcJkQj35T9DgwtYRc/2zM3u8jNwQXKwrUWA==" + ], + "priority": ["100"], + "algorithm": ["RSA-OAEP"] + } + }, + { + "id": "ce5dcd75-614d-453a-868c-4413b4a10c39", + "name": "hmac-generated-hs512", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "kid": ["a58f2df5-d24b-4aae-9e38-d42736883c7d"], + "secret": [ + "4sDZ4TC6Cuo0-A5Wa42n_HLCxFj6ir4enL6OmdllOTtR7f5YJN5bsPOJXOFGHeuNPe5jgNq2GfOaeqyQ19PnJMd3Ctsj7vQlx57hywXNvQ1FNuKL1uoxF2Szvw65Y4gIM7xoZpQglVhg2Zh7kA3HJEVhDvnmjNdjtm1QgdlFYws" + ], + "priority": ["100"], + "algorithm": ["HS512"] + } + }, + { + "id": "972a70cc-5e9d-4435-8423-f4d32e18d1e7", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "privateKey": [ + "MIIEogIBAAKCAQEAy3EHaNAy6udZMC3A2KIZhMDg0SfGN+FVOKRJfh6aJwtNPuP6EXUhCMRSCXj3EHvFYrBJwKllC8li8MC5rw0vF/P9OY1zdbNkg8Rpwa1D55AS/MlYqiKHazKIV55SXVt5MKtjGATk9D4P/UZ8iP3viBnT0Kws4lWrAv1Uk12CkeLzojeTdCr4I8xgsj5U6dWu2f9DJlsieBhefgJpIXgdWXzVyGC3dOQOrCMHxYdyL4dbBlJPk13QJGkmgH65PnRB0Zu4CtlNHWN1jbXWcRNs8iMLZ4R36F8OzbMcv51lv7+0UTP7HJ4iRjw+sSlUH1AB+3sklyoNgRnW6sisEA+UFQIDAQABAoIBAA9kbWGWQwv31g0poQoi9ZhQOZJJlps6vsZq066ppRMoLT+BYzW37Xhq1iQmVVcXbj9BxErB5kXGhmhdxI7EihgfWzzkAWTZ3lSD41aGg/k8stsSZtV0iFdpetxaO7QZjClNBlHWaPY7zdzlXN3GjL146shChqDXR3mR7ji6HftolGVnmzUXRK+gZG9IirlC+qCJ+sd6m9h83x31X5PRT6yiJ/jeNN4XpuMh61xHFckFOFCGfV2isWM9qL5kLllN1+m8nMjt0HOeEB0GRrHTMSp7QC9RI0z1C/uxdAdSyMhCUtva8jAfjtqYAo7yc63zlOvlkFuYeOQ9X8UmnavBbL8CgYEA7FjyjVr3OK139528/FJMmLk2xOCDQ08pS+ADX5Eib7R62k1ZzXiKnv/8whfdQFeJwIunSYn+y2JCaMFjARrh04SELeH6/CvQ5uCknfIkLeNBij1ye5Ruy7JpaV3oe36h8sJYv1+p5RcrxxINBxbEeKM/YQWRwcXVE54MBCB4dKsCgYEA3FufmasbB4Pna2Txlgo+XCKpf+1U+gcN6lRzsKzqtFVT7+ofUndnqTKgPrLHYytYOFIZIIP8YZBno5gUvK7bFjgAGWacayYNWAXSiEhRQ3ah95Ii/b4lcU095GN/Xu68yqlGQc0GDVD9xRejBNyYgHc2GPQ9bigjsb6pQLy0mj8CgYAN5SjVcKyqM2CjOS3cM8Z3ECSNLJnrAiNuZ4wrOTAqGxVB8lw+PUEBGhG1I4wJdVwO6ub55tgJAwzedcgpT3hJZDgVLn0ACF9uw3RKKOtBm2PGCdjKNS7SYPnbjP7XC9nfmNd44NnvMw6K1J/Zc9g3M3nNbXNlTgk57wfL0lDiowKBgEIF4cf1EGAsEUaINCo0X4LTj92YioFvY6f2LcOdy6TEfCXCDCh1RkXXuVOP1VXNQt19G7I2WYQR9Dt78Zqm+VWq6byyleM0v4LEG9Rhdpe0D8tRqdJFCorsDcNEXIFhHofKOBa3Cz0qKx7Gej2Wqsqy7S6E33MF68vxyFxxLduZAoGAcHhDa8r7EMFTEt3rZIqmblqOYvhfMKJ+Ruom11mUSHWLgyQGzK8mVPhB59J7gt0DKU6XRIwby/7c7x2wFWQ+dsy03PN49PDtewLcGtrsicJlY2mofFZpsFsYhOpyhPg4/zFiX77Ev3UEYiJJ4qXnlV5Yb+ae5D8ZNlmhIP1HQY4=" + ], + "keyUse": ["SIG"], + "certificate": [ + "MIICnTCCAYUCBgGVU7avAzANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAd0ZWFjaGVyMB4XDTI1MDMwMTIxNTUzNloXDTM1MDMwMTIxNTcxNlowEjEQMA4GA1UEAwwHdGVhY2hlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMtxB2jQMurnWTAtwNiiGYTA4NEnxjfhVTikSX4emicLTT7j+hF1IQjEUgl49xB7xWKwScCpZQvJYvDAua8NLxfz/TmNc3WzZIPEacGtQ+eQEvzJWKoih2syiFeeUl1beTCrYxgE5PQ+D/1GfIj974gZ09CsLOJVqwL9VJNdgpHi86I3k3Qq+CPMYLI+VOnVrtn/QyZbIngYXn4CaSF4HVl81chgt3TkDqwjB8WHci+HWwZST5Nd0CRpJoB+uT50QdGbuArZTR1jdY211nETbPIjC2eEd+hfDs2zHL+dZb+/tFEz+xyeIkY8PrEpVB9QAft7JJcqDYEZ1urIrBAPlBUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAHkOqsY1iHqqCMDFvTh/XCNZRwdLdGY6ev+5zShrgb8MPJNgM/HIqQtwQ9wuKf5RfMF1+FQdSU1eavTeuHXp4IuMgv97DAjdZ/pBGHz5tCWMdlaf+Au/1zDoqCV91CbGuV6WHaUhDJLZfp9/phiq2BzPZO6LeWhFJLMzH+N6rPZ7Om72rjTN31TlLLgmLuKlOhMp2QpyaQB16g4ksLGIYq7IXIbCqPRuB33k3gO/+ZMYRpU2U4DQ3FZyIe4LzLXQQ7VSFz/x/rvnbF+hHBdcbszUvsQYCS21aZ6nAq4CGinU2iAOLXHmFotKs+01KZT1N3ZGlGQmHM8ywYyb9qbcfPA==" + ], + "priority": ["100"] + } + }, + { + "id": "24e3094f-f962-49bd-b355-ff3096bfefe8", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "kid": ["52ac32c1-f589-4e04-9667-16d2e7bd707a"], + "secret": ["ZEiWoUCZ30PSKa2rx8UXTQ"], + "priority": ["100"] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "2ac7aebb-c1ac-4fdf-9687-cedd34665024", + "alias": "Account verification options", + "description": "Method with which to verity the existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-email-verification", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false + } + ] + }, + { + "id": "2505f3dc-719b-43a1-9631-585302dd449e", + "alias": "Browser - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "5a07c120-c34b-4cf2-b38d-2e558af6853a", + "alias": "Browser - Conditional Organization", + "description": "Flow to determine if the organization identity-first login is to be used", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "organization", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "a3317f52-b2bc-4b4c-af14-53901d253fca", + "alias": "Direct Grant - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "2281818c-fb40-4997-a1ad-fc9ad2c3cacc", + "alias": "First Broker Login - Conditional Organization", + "description": "Flow to determine if the authenticator that adds organization members is to be used", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "idp-add-organization-member", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "fcab0380-ca38-4f66-aaf2-ec741ef8be8e", + "alias": "First broker login - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "ae2e214a-82b6-4d78-a7d0-f80d454e5083", + "alias": "Handle Existing Account", + "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-confirm-link", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Account verification options", + "userSetupAllowed": false + } + ] + }, + { + "id": "ad2add46-e1bb-47bf-a125-d76c517f66a4", + "alias": "Organization", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional Organization", + "userSetupAllowed": false + } + ] + }, + { + "id": "74e5d429-4db2-4323-b504-005c03e530fc", + "alias": "Reset - Conditional OTP", + "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "d11dbfe7-2472-4cda-a7f5-e9a536154028", + "alias": "User creation or linking", + "description": "Flow for the existing/non-existing user alternatives", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false + } + ] + }, + { + "id": "f1131dc8-ea34-48e1-9363-438c15f985a4", + "alias": "Verify Existing Account by Re-authentication", + "description": "Reauthentication of existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "First broker login - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "f2880986-ef01-4199-ac31-35e0b16c989b", + "alias": "browser", + "description": "Browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "identity-provider-redirector", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 25, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 26, + "autheticatorFlow": true, + "flowAlias": "Organization", + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "forms", + "userSetupAllowed": false + } + ] + }, + { + "id": "a08dca2e-d491-483f-a310-25bcfa2d89b3", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-secret-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-x509", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "4742ab83-03c9-417d-ba61-017d9f02afb3", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "Direct Grant - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "458f78fd-84e5-4e4d-8198-200f25942134", + "alias": "docker auth", + "description": "Used by Docker clients to authenticate against the IDP", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "docker-http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "8cbdd82f-3794-4fce-9494-70279a3d1fcb", + "alias": "first broker login", + "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "review profile config", + "authenticator": "idp-review-profile", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "User creation or linking", + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 50, + "autheticatorFlow": true, + "flowAlias": "First Broker Login - Conditional Organization", + "userSetupAllowed": false + } + ] + }, + { + "id": "b64919c6-da2b-4e66-bcc6-0112d9e3132b", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "3c8979fe-c98c-4911-b16c-510dba8fb8e3", + "alias": "registration", + "description": "Registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "registration form", + "userSetupAllowed": false + } + ] + }, + { + "id": "6f598384-bb66-485e-8ed5-7da83c1deba1", + "alias": "registration form", + "description": "Registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-password-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 50, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-recaptcha-action", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 60, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-terms-and-conditions", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 70, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "086acb80-23bb-496d-a982-0d8886b2e844", + "alias": "reset credentials", + "description": "Reset credentials for a user if they forgot their password or something", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "reset-credentials-choose-user", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-credential-email", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 40, + "autheticatorFlow": true, + "flowAlias": "Reset - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "2b5042d2-f5e2-456c-bd94-1f23ea0bfb20", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "3007c3b0-cdd5-4464-93f4-23e439b15253", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "ce14faa0-34fe-496f-bcb5-a7e72fcf3fbb", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + } + ], + "requiredActions": [ + { + "alias": "CONFIGURE_TOTP", + "name": "Configure OTP", + "providerId": "CONFIGURE_TOTP", + "enabled": true, + "defaultAction": false, + "priority": 10, + "config": {} + }, + { + "alias": "TERMS_AND_CONDITIONS", + "name": "Terms and Conditions", + "providerId": "TERMS_AND_CONDITIONS", + "enabled": false, + "defaultAction": false, + "priority": 20, + "config": {} + }, + { + "alias": "UPDATE_PASSWORD", + "name": "Update Password", + "providerId": "UPDATE_PASSWORD", + "enabled": true, + "defaultAction": false, + "priority": 30, + "config": {} + }, + { + "alias": "UPDATE_PROFILE", + "name": "Update Profile", + "providerId": "UPDATE_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 40, + "config": {} + }, + { + "alias": "VERIFY_EMAIL", + "name": "Verify Email", + "providerId": "VERIFY_EMAIL", + "enabled": true, + "defaultAction": false, + "priority": 50, + "config": {} + }, + { + "alias": "delete_account", + "name": "Delete Account", + "providerId": "delete_account", + "enabled": false, + "defaultAction": false, + "priority": 60, + "config": {} + }, + { + "alias": "webauthn-register", + "name": "Webauthn Register", + "providerId": "webauthn-register", + "enabled": true, + "defaultAction": false, + "priority": 70, + "config": {} + }, + { + "alias": "webauthn-register-passwordless", + "name": "Webauthn Register Passwordless", + "providerId": "webauthn-register-passwordless", + "enabled": true, + "defaultAction": false, + "priority": 80, + "config": {} + }, + { + "alias": "VERIFY_PROFILE", + "name": "Verify Profile", + "providerId": "VERIFY_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 90, + "config": {} + }, + { + "alias": "delete_credential", + "name": "Delete Credential", + "providerId": "delete_credential", + "enabled": true, + "defaultAction": false, + "priority": 100, + "config": {} + }, + { + "alias": "update_user_locale", + "name": "Update User Locale", + "providerId": "update_user_locale", + "enabled": true, + "defaultAction": false, + "priority": 1000, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "firstBrokerLoginFlow": "first broker login", + "attributes": { + "cibaBackchannelTokenDeliveryMode": "poll", + "cibaExpiresIn": "120", + "cibaAuthRequestedUserHint": "login_hint", + "oauth2DeviceCodeLifespan": "600", + "oauth2DevicePollingInterval": "5", + "parRequestUriLifespan": "60", + "cibaInterval": "5", + "realmReusableOtpCode": "false" + }, + "keycloakVersion": "26.1.3", + "userManagedAccessAllowed": false, + "organizationsEnabled": false, + "verifiableCredentialsEnabled": false, + "adminPermissionsEnabled": false, + "clientProfiles": { + "profiles": [] + }, + "clientPolicies": { + "policies": [] } - }, - "groups" : [ ], - "defaultRole" : { - "id" : "6b546a34-4ebe-4c09-b274-fc1f6bebdf93", - "name" : "default-roles-teacher", - "description" : "${role_default-roles}", - "composite" : true, - "clientRole" : false, - "containerId" : "02ba6887-22f5-4de4-ad9b-cb2a2060bce1" - }, - "requiredCredentials" : [ "password" ], - "otpPolicyType" : "totp", - "otpPolicyAlgorithm" : "HmacSHA1", - "otpPolicyInitialCounter" : 0, - "otpPolicyDigits" : 6, - "otpPolicyLookAheadWindow" : 1, - "otpPolicyPeriod" : 30, - "otpPolicyCodeReusable" : false, - "otpSupportedApplications" : [ "totpAppFreeOTPName", "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName" ], - "localizationTexts" : { }, - "webAuthnPolicyRpEntityName" : "keycloak", - "webAuthnPolicySignatureAlgorithms" : [ "ES256", "RS256" ], - "webAuthnPolicyRpId" : "", - "webAuthnPolicyAttestationConveyancePreference" : "not specified", - "webAuthnPolicyAuthenticatorAttachment" : "not specified", - "webAuthnPolicyRequireResidentKey" : "not specified", - "webAuthnPolicyUserVerificationRequirement" : "not specified", - "webAuthnPolicyCreateTimeout" : 0, - "webAuthnPolicyAvoidSameAuthenticatorRegister" : false, - "webAuthnPolicyAcceptableAaguids" : [ ], - "webAuthnPolicyExtraOrigins" : [ ], - "webAuthnPolicyPasswordlessRpEntityName" : "keycloak", - "webAuthnPolicyPasswordlessSignatureAlgorithms" : [ "ES256", "RS256" ], - "webAuthnPolicyPasswordlessRpId" : "", - "webAuthnPolicyPasswordlessAttestationConveyancePreference" : "not specified", - "webAuthnPolicyPasswordlessAuthenticatorAttachment" : "not specified", - "webAuthnPolicyPasswordlessRequireResidentKey" : "not specified", - "webAuthnPolicyPasswordlessUserVerificationRequirement" : "not specified", - "webAuthnPolicyPasswordlessCreateTimeout" : 0, - "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false, - "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ], - "webAuthnPolicyPasswordlessExtraOrigins" : [ ], - "users" : [ { - "id" : "63dbbb64-c09f-4e4e-9cbf-af9e557dbb09", - "username" : "testleerkracht1", - "firstName" : "Kris", - "lastName" : "Coolsaet", - "email" : "kris.coolsaet@ugent.be", - "emailVerified" : false, - "createdTimestamp" : 1740866530658, - "enabled" : true, - "totp" : false, - "credentials" : [ { - "id" : "c5382bf7-ccc6-47de-93b9-2c11ea7b6862", - "type" : "password", - "userLabel" : "My password", - "createdDate" : 1740866544032, - "secretData" : "{\"value\":\"H2vKyHF3j/alz6CNap2uaKSRb+/wrWImVecj7dcHe1w=\",\"salt\":\"32WjW1KzFaR5RJqU0Pfq9w==\",\"additionalParameters\":{}}", - "credentialData" : "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}" - } ], - "disableableCredentialTypes" : [ ], - "requiredActions" : [ ], - "realmRoles" : [ "default-roles-teacher" ], - "notBefore" : 0, - "groups" : [ ] - } ], - "scopeMappings" : [ { - "clientScope" : "offline_access", - "roles" : [ "offline_access" ] - } ], - "clientScopeMappings" : { - "account" : [ { - "client" : "account-console", - "roles" : [ "manage-account", "view-groups" ] - } ] - }, - "clients" : [ { - "id" : "7ceb65eb-30da-4dc3-95bc-f06863362fd6", - "clientId" : "account", - "name" : "${client_account}", - "rootUrl" : "${authBaseUrl}", - "baseUrl" : "/realms/teacher/account/", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ "/realms/teacher/account/*" ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "false", - "post.logout.redirect.uris" : "+" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "web-origins", "acr", "roles", "profile", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - }, { - "id" : "920e8621-36b5-4046-b1cd-4b293668f64b", - "clientId" : "account-console", - "name" : "${client_account-console}", - "rootUrl" : "${authBaseUrl}", - "baseUrl" : "/realms/teacher/account/", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ "/realms/teacher/account/*" ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "false", - "post.logout.redirect.uris" : "+", - "pkce.code.challenge.method" : "S256" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "protocolMappers" : [ { - "id" : "cd3f4ae0-3008-488b-88c5-b6d640a9edd3", - "name" : "audience resolve", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-audience-resolve-mapper", - "consentRequired" : false, - "config" : { } - } ], - "defaultClientScopes" : [ "web-origins", "acr", "roles", "profile", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - }, { - "id" : "9d7b2827-b7bb-451e-ad38-8f55a69f7c9c", - "clientId" : "admin-cli", - "name" : "${client_admin-cli}", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : false, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : true, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "false", - "client.use.lightweight.access.token.enabled" : "true" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : true, - "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "web-origins", "acr", "roles", "profile", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - }, { - "id" : "cfd0202e-a6b9-4c5e-9f49-2ef17df9089b", - "clientId" : "broker", - "name" : "${client_broker}", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : true, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : false, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "true" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "web-origins", "acr", "roles", "profile", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - }, { - "id" : "abdee18a-4549-48b5-b976-4c1a42820ef9", - "clientId" : "dwengo", - "name" : "Dwengo", - "description" : "", - "rootUrl" : "http://localhost:5173", - "adminUrl" : "http://localhost:5173", - "baseUrl" : "http://localhost:5173", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ "urn:ietf:wg:oauth:2.0:oob", "http://localhost:5173/*", "http://localhost:5173" ], - "webOrigins" : [ "+" ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : true, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : true, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "false", - "oidc.ciba.grant.enabled" : "false", - "backchannel.logout.session.required" : "true", - "post.logout.redirect.uris" : "+", - "frontchannel.logout.session.required" : "true", - "oauth2.device.authorization.grant.enabled" : "false", - "display.on.consent.screen" : "false", - "backchannel.logout.revoke.offline.tokens" : "false" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : true, - "nodeReRegistrationTimeout" : -1, - "defaultClientScopes" : [ "web-origins", "acr", "roles", "profile", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - }, { - "id" : "112e0e97-df75-4ed7-a35f-03b7c5f9d36a", - "clientId" : "realm-management", - "name" : "${client_realm-management}", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : true, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : false, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "true" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "web-origins", "acr", "roles", "profile", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - }, { - "id" : "c421853c-5bdf-4ea9-ae97-51f5ad7b8df8", - "clientId" : "security-admin-console", - "name" : "${client_security-admin-console}", - "rootUrl" : "${authAdminUrl}", - "baseUrl" : "/admin/teacher/console/", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ "/admin/teacher/console/*" ], - "webOrigins" : [ "+" ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "false", - "client.use.lightweight.access.token.enabled" : "true", - "post.logout.redirect.uris" : "+", - "pkce.code.challenge.method" : "S256" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : true, - "nodeReRegistrationTimeout" : 0, - "protocolMappers" : [ { - "id" : "a9a893af-925e-46c9-ba33-47b06101ce5f", - "name" : "locale", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "locale", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "locale", - "jsonType.label" : "String" - } - } ], - "defaultClientScopes" : [ "web-origins", "acr", "roles", "profile", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - } ], - "clientScopes" : [ { - "id" : "fef4fbeb-d7e6-4474-b802-6c63df0dc9a3", - "name" : "saml_organization", - "description" : "Organization Membership", - "protocol" : "saml", - "attributes" : { - "display.on.consent.screen" : "false" - }, - "protocolMappers" : [ { - "id" : "2384b79b-5cc3-4e1c-b4b2-4bee2ceeed72", - "name" : "organization", - "protocol" : "saml", - "protocolMapper" : "saml-organization-membership-mapper", - "consentRequired" : false, - "config" : { } - } ] - }, { - "id" : "a097893c-7eed-4556-b2ed-3751c7fc3c51", - "name" : "offline_access", - "description" : "OpenID Connect built-in scope: offline_access", - "protocol" : "openid-connect", - "attributes" : { - "consent.screen.text" : "${offlineAccessScopeConsentText}", - "display.on.consent.screen" : "true" - } - }, { - "id" : "ffc38cb2-eb10-47cf-a2d6-6647fdd4da65", - "name" : "service_account", - "description" : "Specific scope for a client enabled for service accounts", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "display.on.consent.screen" : "false" - }, - "protocolMappers" : [ { - "id" : "06ed3629-1c3d-48d9-80c6-98fcd3958c48", - "name" : "Client Host", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usersessionmodel-note-mapper", - "consentRequired" : false, - "config" : { - "user.session.note" : "clientHost", - "id.token.claim" : "true", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "clientHost", - "jsonType.label" : "String" - } - }, { - "id" : "04eeb81e-05c0-484a-91df-9a79138bcd66", - "name" : "Client IP Address", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usersessionmodel-note-mapper", - "consentRequired" : false, - "config" : { - "user.session.note" : "clientAddress", - "id.token.claim" : "true", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "clientAddress", - "jsonType.label" : "String" - } - }, { - "id" : "6e673f49-ce38-4583-8040-8a2e7ec5e7c8", - "name" : "Client ID", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usersessionmodel-note-mapper", - "consentRequired" : false, - "config" : { - "user.session.note" : "client_id", - "id.token.claim" : "true", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "client_id", - "jsonType.label" : "String" - } - } ] - }, { - "id" : "ee188d9c-ab26-4e53-a16c-c9f77094f854", - "name" : "profile", - "description" : "OpenID Connect built-in scope: profile", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "consent.screen.text" : "${profileScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "05ff270b-6a50-4bbb-903d-9546a59f20bf", - "name" : "picture", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "picture", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "picture", - "jsonType.label" : "String" - } - }, { - "id" : "394f808d-bc7b-476e-a372-7cfece5c6db0", - "name" : "gender", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "gender", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "gender", - "jsonType.label" : "String" - } - }, { - "id" : "0371c44f-c6e0-4f88-ac8f-17a56e2b90f8", - "name" : "profile", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "profile", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "profile", - "jsonType.label" : "String" - } - }, { - "id" : "21d66073-42f2-443b-aac4-e49c9038253c", - "name" : "birthdate", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "birthdate", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "birthdate", - "jsonType.label" : "String" - } - }, { - "id" : "5cc6a97f-9d1a-4c72-b682-af6d1bd36883", - "name" : "full name", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-full-name-mapper", - "consentRequired" : false, - "config" : { - "id.token.claim" : "true", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "userinfo.token.claim" : "true" - } - }, { - "id" : "d6a6d46b-80a7-4228-af07-0faae2911fed", - "name" : "nickname", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "nickname", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "nickname", - "jsonType.label" : "String" - } - }, { - "id" : "322b508a-7464-4b0f-90df-3f489975a62e", - "name" : "zoneinfo", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "zoneinfo", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "zoneinfo", - "jsonType.label" : "String" - } - }, { - "id" : "f757ae7a-3005-4899-bb4e-da1ab4b47bb0", - "name" : "locale", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "locale", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "locale", - "jsonType.label" : "String" - } - }, { - "id" : "bab8eb17-0cb0-4275-8456-aa1d65933a35", - "name" : "updated at", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "updatedAt", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "updated_at", - "jsonType.label" : "long" - } - }, { - "id" : "6ea1d43c-d4c7-4f2f-93b0-dfdb3bb584eb", - "name" : "given name", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "firstName", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "given_name", - "jsonType.label" : "String" - } - }, { - "id" : "3a2ebc93-05fb-4904-996b-5e3331b72fcd", - "name" : "family name", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "lastName", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "family_name", - "jsonType.label" : "String" - } - }, { - "id" : "217b417e-d4f6-4225-bf92-3bd38f6fbefb", - "name" : "username", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "username", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "preferred_username", - "jsonType.label" : "String" - } - }, { - "id" : "3dd5da51-5842-4358-a69f-f7ffffe521ac", - "name" : "website", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "website", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "website", - "jsonType.label" : "String" - } - }, { - "id" : "790bda99-1c27-4970-b3b9-4fa1c90c738c", - "name" : "middle name", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "middleName", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "middle_name", - "jsonType.label" : "String" - } - } ] - }, { - "id" : "e6cf59c7-9390-4f48-ab01-79a0fa138960", - "name" : "organization", - "description" : "Additional claims about the organization a subject belongs to", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "consent.screen.text" : "${organizationScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "417ff129-6b95-4e95-9f57-a6699ca18d8d", - "name" : "organization", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-organization-membership-mapper", - "consentRequired" : false, - "config" : { - "id.token.claim" : "true", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "organization", - "jsonType.label" : "String", - "multivalued" : "true" - } - } ] - }, { - "id" : "43d92ef5-76d8-4df0-84b5-5f833875d345", - "name" : "email", - "description" : "OpenID Connect built-in scope: email", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "consent.screen.text" : "${emailScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "74d21718-190a-4c53-b446-b07e5f029394", - "name" : "email verified", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-property-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "emailVerified", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "email_verified", - "jsonType.label" : "boolean" - } - }, { - "id" : "949871a0-d68c-4563-a9b3-945a3148f937", - "name" : "email", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "email", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "email", - "jsonType.label" : "String" - } - } ] - }, { - "id" : "b07a2014-d07e-450f-a593-66e9f9cf4799", - "name" : "acr", - "description" : "OpenID Connect scope for add acr (authentication context class reference) to the token", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "display.on.consent.screen" : "false" - }, - "protocolMappers" : [ { - "id" : "79efdc37-0f06-43e6-a516-7bc9dc29f04d", - "name" : "acr loa level", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-acr-mapper", - "consentRequired" : false, - "config" : { - "id.token.claim" : "true", - "introspection.token.claim" : "true", - "access.token.claim" : "true" - } - } ] - }, { - "id" : "3bbbff21-0446-4813-8bdf-54c35d8fffca", - "name" : "microprofile-jwt", - "description" : "Microprofile - JWT built-in scope", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "display.on.consent.screen" : "false" - }, - "protocolMappers" : [ { - "id" : "0e996cda-fe5b-439d-ba4c-cf2129ae812f", - "name" : "upn", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "username", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "upn", - "jsonType.label" : "String" - } - }, { - "id" : "ddf1efe2-e765-475c-a4a0-d52f1f597834", - "name" : "groups", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-realm-role-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "multivalued" : "true", - "user.attribute" : "foo", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "groups", - "jsonType.label" : "String" - } - } ] - }, { - "id" : "93a40d0e-f163-42f7-a9d4-53cc2e17914e", - "name" : "basic", - "description" : "OpenID Connect scope for add all basic claims to the token", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "display.on.consent.screen" : "false" - }, - "protocolMappers" : [ { - "id" : "41eb9e93-8e04-404b-a12b-40ef5a55f640", - "name" : "sub", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-sub-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "access.token.claim" : "true" - } - }, { - "id" : "1291062a-10f6-4061-b9ea-f54ff5d8ec54", - "name" : "auth_time", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usersessionmodel-note-mapper", - "consentRequired" : false, - "config" : { - "user.session.note" : "AUTH_TIME", - "id.token.claim" : "true", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "auth_time", - "jsonType.label" : "long" - } - } ] - }, { - "id" : "9ea27173-e54b-42f0-8f6c-5a36c5073ede", - "name" : "role_list", - "description" : "SAML role list", - "protocol" : "saml", - "attributes" : { - "consent.screen.text" : "${samlRoleListScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "d10a6975-8aeb-4215-8d6b-23b0286d4abb", - "name" : "role list", - "protocol" : "saml", - "protocolMapper" : "saml-role-list-mapper", - "consentRequired" : false, - "config" : { - "single" : "false", - "attribute.nameformat" : "Basic", - "attribute.name" : "Role" - } - } ] - }, { - "id" : "e8a99a5a-1519-4c7d-a3f0-ac6d34c61a0b", - "name" : "phone", - "description" : "OpenID Connect built-in scope: phone", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "consent.screen.text" : "${phoneScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "b2de087f-169f-44b3-ad46-3a063ac9025f", - "name" : "phone number", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "phoneNumber", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "phone_number", - "jsonType.label" : "String" - } - }, { - "id" : "ffb8aebd-0d03-4811-8fd4-aa03bda36b2d", - "name" : "phone number verified", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "phoneNumberVerified", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "phone_number_verified", - "jsonType.label" : "boolean" - } - } ] - }, { - "id" : "30e06d84-f610-4f17-8820-6f785a510357", - "name" : "address", - "description" : "OpenID Connect built-in scope: address", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "consent.screen.text" : "${addressScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "de707a09-a895-4b67-9ac5-0ff4e69715ea", - "name" : "address", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-address-mapper", - "consentRequired" : false, - "config" : { - "user.attribute.formatted" : "formatted", - "user.attribute.country" : "country", - "introspection.token.claim" : "true", - "user.attribute.postal_code" : "postal_code", - "userinfo.token.claim" : "true", - "user.attribute.street" : "street", - "id.token.claim" : "true", - "user.attribute.region" : "region", - "access.token.claim" : "true", - "user.attribute.locality" : "locality" - } - } ] - }, { - "id" : "1762c903-9f07-451c-915d-855488e4aa42", - "name" : "web-origins", - "description" : "OpenID Connect scope for add allowed web origins to the access token", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "consent.screen.text" : "", - "display.on.consent.screen" : "false" - }, - "protocolMappers" : [ { - "id" : "0164bdc3-c79d-4467-b6bf-ca9a6889d04c", - "name" : "allowed web origins", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-allowed-origins-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "access.token.claim" : "true" - } - } ] - }, { - "id" : "91301d6d-0bb9-4da6-b8db-ee2480e25fee", - "name" : "roles", - "description" : "OpenID Connect scope for add user roles to the access token", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "consent.screen.text" : "${rolesScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "2880d772-b0da-4ee8-bf1e-3f729a945db9", - "name" : "realm roles", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-realm-role-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "foo", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "realm_access.roles", - "jsonType.label" : "String", - "multivalued" : "true" - } - }, { - "id" : "535042c5-58c5-4225-94b8-0b5b3411968e", - "name" : "client roles", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-client-role-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "foo", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "resource_access.${client_id}.roles", - "jsonType.label" : "String", - "multivalued" : "true" - } - }, { - "id" : "a88432f1-565f-480d-958d-a5cea1dbcf0a", - "name" : "audience resolve", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-audience-resolve-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "access.token.claim" : "true" - } - } ] - } ], - "defaultDefaultClientScopes" : [ "role_list", "saml_organization", "profile", "email", "roles", "web-origins", "acr", "basic" ], - "defaultOptionalClientScopes" : [ "offline_access", "address", "phone", "microprofile-jwt", "organization" ], - "browserSecurityHeaders" : { - "contentSecurityPolicyReportOnly" : "", - "xContentTypeOptions" : "nosniff", - "referrerPolicy" : "no-referrer", - "xRobotsTag" : "none", - "xFrameOptions" : "SAMEORIGIN", - "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", - "xXSSProtection" : "1; mode=block", - "strictTransportSecurity" : "max-age=31536000; includeSubDomains" - }, - "smtpServer" : { }, - "eventsEnabled" : false, - "eventsListeners" : [ "jboss-logging" ], - "enabledEventTypes" : [ ], - "adminEventsEnabled" : false, - "adminEventsDetailsEnabled" : false, - "identityProviders" : [ ], - "identityProviderMappers" : [ ], - "components" : { - "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ { - "id" : "a689e06a-e440-4d94-ba54-692fba5a5486", - "name" : "Max Clients Limit", - "providerId" : "max-clients", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { - "max-clients" : [ "200" ] - } - }, { - "id" : "2778fda5-0a9f-40ab-ab4b-054ff8ce38e9", - "name" : "Allowed Client Scopes", - "providerId" : "allowed-client-templates", - "subType" : "authenticated", - "subComponents" : { }, - "config" : { - "allow-default-scopes" : [ "true" ] - } - }, { - "id" : "36dc0167-9c9a-4b4a-9f04-29129aecac4d", - "name" : "Allowed Protocol Mapper Types", - "providerId" : "allowed-protocol-mappers", - "subType" : "authenticated", - "subComponents" : { }, - "config" : { - "allowed-protocol-mapper-types" : [ "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "saml-user-property-mapper", "oidc-address-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper" ] - } - }, { - "id" : "4b79c6fd-5166-4bc2-ab0b-bff0018452f6", - "name" : "Consent Required", - "providerId" : "consent-required", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { } - }, { - "id" : "2003600a-89fb-421e-9dfe-d5096ee7fd4e", - "name" : "Allowed Protocol Mapper Types", - "providerId" : "allowed-protocol-mappers", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { - "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-role-list-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper" ] - } - }, { - "id" : "d62a2e93-f877-462a-bad3-93dcf91d49d2", - "name" : "Trusted Hosts", - "providerId" : "trusted-hosts", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { - "host-sending-registration-request-must-match" : [ "true" ], - "client-uris-must-match" : [ "true" ] - } - }, { - "id" : "6e659a80-a638-4504-b507-21b9f77586ed", - "name" : "Full Scope Disabled", - "providerId" : "scope", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { } - }, { - "id" : "9ef67c59-5c3e-40cf-90ee-516b2e35ed3d", - "name" : "Allowed Client Scopes", - "providerId" : "allowed-client-templates", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { - "allow-default-scopes" : [ "true" ] - } - } ], - "org.keycloak.keys.KeyProvider" : [ { - "id" : "b5365a56-e00d-4612-80bf-262a9c8dba7c", - "name" : "rsa-enc-generated", - "providerId" : "rsa-enc-generated", - "subComponents" : { }, - "config" : { - "privateKey" : [ "MIIEogIBAAKCAQEAudnbEbQij+g9JWYMuyJjF/sKe4fVEd9SrCmkFeAHZ7dEAmEKQcAlvJn1aL99pAm8KV0w9PAZugQx7ZzG6eUm4JLc+LYGJ8G8JDiVR6hIWRQ3k9HGcUwNacHKFlDj4XOeMykwLEo7jrQHAUx82vJO8bKZr2ixZqGc1UUUQNbEVYv0HzxhPKPoFYh9qQ8U6P0r/K9xIusLL6ZzmXx6uXqQuqtse05e5G9xwLjQDDrOKju4s1PJ1GZLt5Db9PGypMeA9J34tGL3O0rQom2WbO7R2GZGX044ZoNw6UnraGTmCxin1ywmwTq3JTb1IZ4DPLH/rucnPuKUb60B5ByPmXW/lQIDAQABAoIBAAlyYrGLbb9RX3xNa+O+O3m+U7nUPXcfWikwo6vN+6pgtScGzjnp3bEwxTnqE+WY7hTPLRwiMTiUmoIYuD6u3HNJW8yTmgv+y8SukJ34FpdakPmlTdg39K2VwWMxgOfWk+nHU/DIZC8chQeinu0VKICeIrQ5Ft1f5SQtEvq5v/iWIql+v2ipxdJ2dSl1NIO0/2S2Lyd7Slab50gbJ3kP0uZggN5IMtNd5GBvAbV+jaT4QWKuyXyHqOnyU/+2WU+XhmVPrX6c29sQg2CilqWf4RzEIeO/FgAiANEPyaAgW6mGtf17K1xsSrusyGMUsNGsGJSd7Q8K2o7g/Jv9V8160iECgYEA2xgKIoZ6+fT7UIDr+5insRr6PIht2WYl+JqibjzNRh+rvp1fjKkmjMOA39V6cvLaAHieSOUerSOD7nQONCedpHe6To1zOG9z5yYGgwa/2c/9eNORJq8vNw/4wXaARVf0mCNaexugPTdYvsSaqwW4+azIbB21xXUfKykLp0SjNfUCgYEA2ShJSZyTIqJ64IHi+Kj/E22ajK2DYBiFgNDmzKrW/ANO5ADumgMhahCcxW28Nw68n25vBWCK4o+6eVg1ldEdB1LxoKOYZAaA+zAiMsGI1/ndxdnlFopuJZguKhYDTmxzT0KcD9mApLKZBnCadGjG3FcdC8i14OK6S9lUIIpCvyECgYBXqWC0u7YMuPatGUhSXJwMAs1I1xWMvJBIziZbkTxY6GchV3pZn3xrKfYwmQvrXjvXoGtEo1gI0oMBL7JXL9qlabpDn9kQJZfsToygdFzi25OBerVDEykDEQLo9W8RT8Xv8YVMaJtOowyBF80CzMFcNMPkbmbCYMBd1ohxHsdm2QKBgGB9RhMvPzFkgLTBAdj7Plujl8hqULWiL6/NIsBOKLhRv/wPbfWA7pfySbZvy/Gq2qT8rNf2zb9dnb3NNAIdqIhYkoSOLGhFe4ohGRD0bZmJrMD80I3zdH2/4MNShKWUCqhtMGraeg60TMpPvlF7POEq0/0ocag7FgwdxQOwa3gBAoGASvjvVtfXyzWA9MycWLvlTPEGW5bjXrroYwulF8DkKfIaKWHfEiulTwQe4SHgS7CzWSg8KgvKIhJC/yTwfOtxZ894G9LWivwjjZCottIE+/qs6ioYSXouQr6IsWxs7U0i3gP36tsePjuSjR06kpBGfcFdynypAAq+mVBCV0Mxk9A=" ], - "keyUse" : [ "ENC" ], - "certificate" : [ "MIICnTCCAYUCBgGVU7avyzANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAd0ZWFjaGVyMB4XDTI1MDMwMTIxNTUzNloXDTM1MDMwMTIxNTcxNlowEjEQMA4GA1UEAwwHdGVhY2hlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALnZ2xG0Io/oPSVmDLsiYxf7CnuH1RHfUqwppBXgB2e3RAJhCkHAJbyZ9Wi/faQJvCldMPTwGboEMe2cxunlJuCS3Pi2BifBvCQ4lUeoSFkUN5PRxnFMDWnByhZQ4+FznjMpMCxKO460BwFMfNryTvGyma9osWahnNVFFEDWxFWL9B88YTyj6BWIfakPFOj9K/yvcSLrCy+mc5l8erl6kLqrbHtOXuRvccC40Aw6zio7uLNTydRmS7eQ2/TxsqTHgPSd+LRi9ztK0KJtlmzu0dhmRl9OOGaDcOlJ62hk5gsYp9csJsE6tyU29SGeAzyx/67nJz7ilG+tAeQcj5l1v5UCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAf3HTufrfWb0uqsEwfUETl4S4IbJOjqDdzFhUkMVtiq5I9LLUlJ7StZ6eoDCEoKUzF2lPy0qR2Om7IKC8BA7J5qUio0NSNh9j/t1Ipcjzx6SQI2cD6AjJFZndnF+OBTxdm9c6J+KMho6ZSMQEGwn2osgRBeItauxUshogQJPY/GzWMHlZyCAJcYtuflzgyw1VIQ0OiWCpCiSGeWpojxh19KR9qSBU1rETZMLokmdp84muq8aqEnNIFY5XRyUdH4gjNBx3TGsammZbvzuZdZIDvFNE19SXl/J9QcWJlRw0DuOblLcLKiamcJkQj35T9DgwtYRc/2zM3u8jNwQXKwrUWA==" ], - "priority" : [ "100" ], - "algorithm" : [ "RSA-OAEP" ] - } - }, { - "id" : "ce5dcd75-614d-453a-868c-4413b4a10c39", - "name" : "hmac-generated-hs512", - "providerId" : "hmac-generated", - "subComponents" : { }, - "config" : { - "kid" : [ "a58f2df5-d24b-4aae-9e38-d42736883c7d" ], - "secret" : [ "4sDZ4TC6Cuo0-A5Wa42n_HLCxFj6ir4enL6OmdllOTtR7f5YJN5bsPOJXOFGHeuNPe5jgNq2GfOaeqyQ19PnJMd3Ctsj7vQlx57hywXNvQ1FNuKL1uoxF2Szvw65Y4gIM7xoZpQglVhg2Zh7kA3HJEVhDvnmjNdjtm1QgdlFYws" ], - "priority" : [ "100" ], - "algorithm" : [ "HS512" ] - } - }, { - "id" : "972a70cc-5e9d-4435-8423-f4d32e18d1e7", - "name" : "rsa-generated", - "providerId" : "rsa-generated", - "subComponents" : { }, - "config" : { - "privateKey" : [ "MIIEogIBAAKCAQEAy3EHaNAy6udZMC3A2KIZhMDg0SfGN+FVOKRJfh6aJwtNPuP6EXUhCMRSCXj3EHvFYrBJwKllC8li8MC5rw0vF/P9OY1zdbNkg8Rpwa1D55AS/MlYqiKHazKIV55SXVt5MKtjGATk9D4P/UZ8iP3viBnT0Kws4lWrAv1Uk12CkeLzojeTdCr4I8xgsj5U6dWu2f9DJlsieBhefgJpIXgdWXzVyGC3dOQOrCMHxYdyL4dbBlJPk13QJGkmgH65PnRB0Zu4CtlNHWN1jbXWcRNs8iMLZ4R36F8OzbMcv51lv7+0UTP7HJ4iRjw+sSlUH1AB+3sklyoNgRnW6sisEA+UFQIDAQABAoIBAA9kbWGWQwv31g0poQoi9ZhQOZJJlps6vsZq066ppRMoLT+BYzW37Xhq1iQmVVcXbj9BxErB5kXGhmhdxI7EihgfWzzkAWTZ3lSD41aGg/k8stsSZtV0iFdpetxaO7QZjClNBlHWaPY7zdzlXN3GjL146shChqDXR3mR7ji6HftolGVnmzUXRK+gZG9IirlC+qCJ+sd6m9h83x31X5PRT6yiJ/jeNN4XpuMh61xHFckFOFCGfV2isWM9qL5kLllN1+m8nMjt0HOeEB0GRrHTMSp7QC9RI0z1C/uxdAdSyMhCUtva8jAfjtqYAo7yc63zlOvlkFuYeOQ9X8UmnavBbL8CgYEA7FjyjVr3OK139528/FJMmLk2xOCDQ08pS+ADX5Eib7R62k1ZzXiKnv/8whfdQFeJwIunSYn+y2JCaMFjARrh04SELeH6/CvQ5uCknfIkLeNBij1ye5Ruy7JpaV3oe36h8sJYv1+p5RcrxxINBxbEeKM/YQWRwcXVE54MBCB4dKsCgYEA3FufmasbB4Pna2Txlgo+XCKpf+1U+gcN6lRzsKzqtFVT7+ofUndnqTKgPrLHYytYOFIZIIP8YZBno5gUvK7bFjgAGWacayYNWAXSiEhRQ3ah95Ii/b4lcU095GN/Xu68yqlGQc0GDVD9xRejBNyYgHc2GPQ9bigjsb6pQLy0mj8CgYAN5SjVcKyqM2CjOS3cM8Z3ECSNLJnrAiNuZ4wrOTAqGxVB8lw+PUEBGhG1I4wJdVwO6ub55tgJAwzedcgpT3hJZDgVLn0ACF9uw3RKKOtBm2PGCdjKNS7SYPnbjP7XC9nfmNd44NnvMw6K1J/Zc9g3M3nNbXNlTgk57wfL0lDiowKBgEIF4cf1EGAsEUaINCo0X4LTj92YioFvY6f2LcOdy6TEfCXCDCh1RkXXuVOP1VXNQt19G7I2WYQR9Dt78Zqm+VWq6byyleM0v4LEG9Rhdpe0D8tRqdJFCorsDcNEXIFhHofKOBa3Cz0qKx7Gej2Wqsqy7S6E33MF68vxyFxxLduZAoGAcHhDa8r7EMFTEt3rZIqmblqOYvhfMKJ+Ruom11mUSHWLgyQGzK8mVPhB59J7gt0DKU6XRIwby/7c7x2wFWQ+dsy03PN49PDtewLcGtrsicJlY2mofFZpsFsYhOpyhPg4/zFiX77Ev3UEYiJJ4qXnlV5Yb+ae5D8ZNlmhIP1HQY4=" ], - "keyUse" : [ "SIG" ], - "certificate" : [ "MIICnTCCAYUCBgGVU7avAzANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAd0ZWFjaGVyMB4XDTI1MDMwMTIxNTUzNloXDTM1MDMwMTIxNTcxNlowEjEQMA4GA1UEAwwHdGVhY2hlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMtxB2jQMurnWTAtwNiiGYTA4NEnxjfhVTikSX4emicLTT7j+hF1IQjEUgl49xB7xWKwScCpZQvJYvDAua8NLxfz/TmNc3WzZIPEacGtQ+eQEvzJWKoih2syiFeeUl1beTCrYxgE5PQ+D/1GfIj974gZ09CsLOJVqwL9VJNdgpHi86I3k3Qq+CPMYLI+VOnVrtn/QyZbIngYXn4CaSF4HVl81chgt3TkDqwjB8WHci+HWwZST5Nd0CRpJoB+uT50QdGbuArZTR1jdY211nETbPIjC2eEd+hfDs2zHL+dZb+/tFEz+xyeIkY8PrEpVB9QAft7JJcqDYEZ1urIrBAPlBUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAHkOqsY1iHqqCMDFvTh/XCNZRwdLdGY6ev+5zShrgb8MPJNgM/HIqQtwQ9wuKf5RfMF1+FQdSU1eavTeuHXp4IuMgv97DAjdZ/pBGHz5tCWMdlaf+Au/1zDoqCV91CbGuV6WHaUhDJLZfp9/phiq2BzPZO6LeWhFJLMzH+N6rPZ7Om72rjTN31TlLLgmLuKlOhMp2QpyaQB16g4ksLGIYq7IXIbCqPRuB33k3gO/+ZMYRpU2U4DQ3FZyIe4LzLXQQ7VSFz/x/rvnbF+hHBdcbszUvsQYCS21aZ6nAq4CGinU2iAOLXHmFotKs+01KZT1N3ZGlGQmHM8ywYyb9qbcfPA==" ], - "priority" : [ "100" ] - } - }, { - "id" : "24e3094f-f962-49bd-b355-ff3096bfefe8", - "name" : "aes-generated", - "providerId" : "aes-generated", - "subComponents" : { }, - "config" : { - "kid" : [ "52ac32c1-f589-4e04-9667-16d2e7bd707a" ], - "secret" : [ "ZEiWoUCZ30PSKa2rx8UXTQ" ], - "priority" : [ "100" ] - } - } ] - }, - "internationalizationEnabled" : false, - "supportedLocales" : [ ], - "authenticationFlows" : [ { - "id" : "2ac7aebb-c1ac-4fdf-9687-cedd34665024", - "alias" : "Account verification options", - "description" : "Method with which to verity the existing account", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "idp-email-verification", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "ALTERNATIVE", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "Verify Existing Account by Re-authentication", - "userSetupAllowed" : false - } ] - }, { - "id" : "2505f3dc-719b-43a1-9631-585302dd449e", - "alias" : "Browser - Conditional OTP", - "description" : "Flow to determine if the OTP is required for the authentication", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "auth-otp-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "5a07c120-c34b-4cf2-b38d-2e558af6853a", - "alias" : "Browser - Conditional Organization", - "description" : "Flow to determine if the organization identity-first login is to be used", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "organization", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "a3317f52-b2bc-4b4c-af14-53901d253fca", - "alias" : "Direct Grant - Conditional OTP", - "description" : "Flow to determine if the OTP is required for the authentication", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "direct-grant-validate-otp", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "2281818c-fb40-4997-a1ad-fc9ad2c3cacc", - "alias" : "First Broker Login - Conditional Organization", - "description" : "Flow to determine if the authenticator that adds organization members is to be used", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "idp-add-organization-member", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "fcab0380-ca38-4f66-aaf2-ec741ef8be8e", - "alias" : "First broker login - Conditional OTP", - "description" : "Flow to determine if the OTP is required for the authentication", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "auth-otp-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "ae2e214a-82b6-4d78-a7d0-f80d454e5083", - "alias" : "Handle Existing Account", - "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "idp-confirm-link", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "Account verification options", - "userSetupAllowed" : false - } ] - }, { - "id" : "ad2add46-e1bb-47bf-a125-d76c517f66a4", - "alias" : "Organization", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 10, - "autheticatorFlow" : true, - "flowAlias" : "Browser - Conditional Organization", - "userSetupAllowed" : false - } ] - }, { - "id" : "74e5d429-4db2-4323-b504-005c03e530fc", - "alias" : "Reset - Conditional OTP", - "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "reset-otp", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "d11dbfe7-2472-4cda-a7f5-e9a536154028", - "alias" : "User creation or linking", - "description" : "Flow for the existing/non-existing user alternatives", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticatorConfig" : "create unique user config", - "authenticator" : "idp-create-user-if-unique", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "ALTERNATIVE", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "Handle Existing Account", - "userSetupAllowed" : false - } ] - }, { - "id" : "f1131dc8-ea34-48e1-9363-438c15f985a4", - "alias" : "Verify Existing Account by Re-authentication", - "description" : "Reauthentication of existing account", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "idp-username-password-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "First broker login - Conditional OTP", - "userSetupAllowed" : false - } ] - }, { - "id" : "f2880986-ef01-4199-ac31-35e0b16c989b", - "alias" : "browser", - "description" : "Browser based authentication", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "auth-cookie", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "auth-spnego", - "authenticatorFlow" : false, - "requirement" : "DISABLED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "identity-provider-redirector", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 25, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "ALTERNATIVE", - "priority" : 26, - "autheticatorFlow" : true, - "flowAlias" : "Organization", - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "ALTERNATIVE", - "priority" : 30, - "autheticatorFlow" : true, - "flowAlias" : "forms", - "userSetupAllowed" : false - } ] - }, { - "id" : "a08dca2e-d491-483f-a310-25bcfa2d89b3", - "alias" : "clients", - "description" : "Base authentication for clients", - "providerId" : "client-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "client-secret", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "client-jwt", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "client-secret-jwt", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 30, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "client-x509", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 40, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "4742ab83-03c9-417d-ba61-017d9f02afb3", - "alias" : "direct grant", - "description" : "OpenID Connect Resource Owner Grant", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "direct-grant-validate-username", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "direct-grant-validate-password", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 30, - "autheticatorFlow" : true, - "flowAlias" : "Direct Grant - Conditional OTP", - "userSetupAllowed" : false - } ] - }, { - "id" : "458f78fd-84e5-4e4d-8198-200f25942134", - "alias" : "docker auth", - "description" : "Used by Docker clients to authenticate against the IDP", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "docker-http-basic-authenticator", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "8cbdd82f-3794-4fce-9494-70279a3d1fcb", - "alias" : "first broker login", - "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticatorConfig" : "review profile config", - "authenticator" : "idp-review-profile", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "User creation or linking", - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 50, - "autheticatorFlow" : true, - "flowAlias" : "First Broker Login - Conditional Organization", - "userSetupAllowed" : false - } ] - }, { - "id" : "b64919c6-da2b-4e66-bcc6-0112d9e3132b", - "alias" : "forms", - "description" : "Username, password, otp and other auth forms.", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "auth-username-password-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "Browser - Conditional OTP", - "userSetupAllowed" : false - } ] - }, { - "id" : "3c8979fe-c98c-4911-b16c-510dba8fb8e3", - "alias" : "registration", - "description" : "Registration flow", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "registration-page-form", - "authenticatorFlow" : true, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : true, - "flowAlias" : "registration form", - "userSetupAllowed" : false - } ] - }, { - "id" : "6f598384-bb66-485e-8ed5-7da83c1deba1", - "alias" : "registration form", - "description" : "Registration form", - "providerId" : "form-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "registration-user-creation", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "registration-password-action", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 50, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "registration-recaptcha-action", - "authenticatorFlow" : false, - "requirement" : "DISABLED", - "priority" : 60, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "registration-terms-and-conditions", - "authenticatorFlow" : false, - "requirement" : "DISABLED", - "priority" : 70, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "086acb80-23bb-496d-a982-0d8886b2e844", - "alias" : "reset credentials", - "description" : "Reset credentials for a user if they forgot their password or something", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "reset-credentials-choose-user", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "reset-credential-email", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "reset-password", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 30, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 40, - "autheticatorFlow" : true, - "flowAlias" : "Reset - Conditional OTP", - "userSetupAllowed" : false - } ] - }, { - "id" : "2b5042d2-f5e2-456c-bd94-1f23ea0bfb20", - "alias" : "saml ecp", - "description" : "SAML ECP Profile Authentication Flow", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "http-basic-authenticator", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - } ], - "authenticatorConfig" : [ { - "id" : "3007c3b0-cdd5-4464-93f4-23e439b15253", - "alias" : "create unique user config", - "config" : { - "require.password.update.after.registration" : "false" - } - }, { - "id" : "ce14faa0-34fe-496f-bcb5-a7e72fcf3fbb", - "alias" : "review profile config", - "config" : { - "update.profile.on.first.login" : "missing" - } - } ], - "requiredActions" : [ { - "alias" : "CONFIGURE_TOTP", - "name" : "Configure OTP", - "providerId" : "CONFIGURE_TOTP", - "enabled" : true, - "defaultAction" : false, - "priority" : 10, - "config" : { } - }, { - "alias" : "TERMS_AND_CONDITIONS", - "name" : "Terms and Conditions", - "providerId" : "TERMS_AND_CONDITIONS", - "enabled" : false, - "defaultAction" : false, - "priority" : 20, - "config" : { } - }, { - "alias" : "UPDATE_PASSWORD", - "name" : "Update Password", - "providerId" : "UPDATE_PASSWORD", - "enabled" : true, - "defaultAction" : false, - "priority" : 30, - "config" : { } - }, { - "alias" : "UPDATE_PROFILE", - "name" : "Update Profile", - "providerId" : "UPDATE_PROFILE", - "enabled" : true, - "defaultAction" : false, - "priority" : 40, - "config" : { } - }, { - "alias" : "VERIFY_EMAIL", - "name" : "Verify Email", - "providerId" : "VERIFY_EMAIL", - "enabled" : true, - "defaultAction" : false, - "priority" : 50, - "config" : { } - }, { - "alias" : "delete_account", - "name" : "Delete Account", - "providerId" : "delete_account", - "enabled" : false, - "defaultAction" : false, - "priority" : 60, - "config" : { } - }, { - "alias" : "webauthn-register", - "name" : "Webauthn Register", - "providerId" : "webauthn-register", - "enabled" : true, - "defaultAction" : false, - "priority" : 70, - "config" : { } - }, { - "alias" : "webauthn-register-passwordless", - "name" : "Webauthn Register Passwordless", - "providerId" : "webauthn-register-passwordless", - "enabled" : true, - "defaultAction" : false, - "priority" : 80, - "config" : { } - }, { - "alias" : "VERIFY_PROFILE", - "name" : "Verify Profile", - "providerId" : "VERIFY_PROFILE", - "enabled" : true, - "defaultAction" : false, - "priority" : 90, - "config" : { } - }, { - "alias" : "delete_credential", - "name" : "Delete Credential", - "providerId" : "delete_credential", - "enabled" : true, - "defaultAction" : false, - "priority" : 100, - "config" : { } - }, { - "alias" : "update_user_locale", - "name" : "Update User Locale", - "providerId" : "update_user_locale", - "enabled" : true, - "defaultAction" : false, - "priority" : 1000, - "config" : { } - } ], - "browserFlow" : "browser", - "registrationFlow" : "registration", - "directGrantFlow" : "direct grant", - "resetCredentialsFlow" : "reset credentials", - "clientAuthenticationFlow" : "clients", - "dockerAuthenticationFlow" : "docker auth", - "firstBrokerLoginFlow" : "first broker login", - "attributes" : { - "cibaBackchannelTokenDeliveryMode" : "poll", - "cibaExpiresIn" : "120", - "cibaAuthRequestedUserHint" : "login_hint", - "oauth2DeviceCodeLifespan" : "600", - "oauth2DevicePollingInterval" : "5", - "parRequestUriLifespan" : "60", - "cibaInterval" : "5", - "realmReusableOtpCode" : "false" - }, - "keycloakVersion" : "26.1.3", - "userManagedAccessAllowed" : false, - "organizationsEnabled" : false, - "verifiableCredentialsEnabled" : false, - "adminPermissionsEnabled" : false, - "clientProfiles" : { - "profiles" : [ ] - }, - "clientPolicies" : { - "policies" : [ ] - } } From b23c8f718feb86b01163b9f76116a9a59f5e2eaa Mon Sep 17 00:00:00 2001 From: Laure Jablonski Date: Mon, 10 Mar 2025 15:30:02 +0100 Subject: [PATCH 120/180] docs: readme aangepast met docs over hoe de testen te runnen --- README.md | 6 ++++++ backend/README.md | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/README.md b/README.md index db5b63a4..d75246d0 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,12 @@ De tech-stack bestaat uit: Voor meer informatie over de keuze van deze tech-stack, zie [designkeuzes](https://github.com/SELab-2/Dwengo-1/wiki/Design-keuzes). +## Testen +Voer volgende commando's uit om de te testen: +``` +npm run test +``` + ## Bijdragen aan Dwengo-1 Zie [CONTRIBUTING.md](./CONTRIBUTING.md) voor meer informatie over hoe je kan bijdragen aan Dwengo-1. diff --git a/backend/README.md b/backend/README.md index 76bc8eae..ee0ec44e 100644 --- a/backend/README.md +++ b/backend/README.md @@ -20,3 +20,9 @@ npm run dev npm run build npm run start ``` + +### Tests + +``` +npm run test +``` From 4aa2dfc7d38964d0ed5d78e9d19d723601472c96 Mon Sep 17 00:00:00 2001 From: Laure Jablonski Date: Mon, 10 Mar 2025 15:36:43 +0100 Subject: [PATCH 121/180] docs: verbeterde versie unit tests --- README.md | 2 +- backend/README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d75246d0..77cd53eb 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Voor meer informatie over de keuze van deze tech-stack, zie [designkeuzes](https ## Testen Voer volgende commando's uit om de te testen: ``` -npm run test +npm run test:unit ``` ## Bijdragen aan Dwengo-1 diff --git a/backend/README.md b/backend/README.md index ee0ec44e..3fd9d913 100644 --- a/backend/README.md +++ b/backend/README.md @@ -22,7 +22,7 @@ npm run start ``` ### Tests - +Voer volgend commando uit om de unit tests uit te voeren: ``` -npm run test +npm run test:unit ``` From 8a53baa1255c6ff206b3a4d0ead1d28abbd05478 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 14:57:02 +0000 Subject: [PATCH 122/180] chore(deps): bump axios from 1.8.1 to 1.8.2 Bumps [axios](https://github.com/axios/axios) from 1.8.1 to 1.8.2. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v1.8.1...v1.8.2) --- updated-dependencies: - dependency-name: axios dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- backend/package.json | 2 +- frontend/package.json | 2 +- package-lock.json | 97 ++++++------------------------------------- 3 files changed, 14 insertions(+), 87 deletions(-) diff --git a/backend/package.json b/backend/package.json index 103f98a5..5aac8381 100644 --- a/backend/package.json +++ b/backend/package.json @@ -19,7 +19,7 @@ "@mikro-orm/reflection": "^6.4.6", "@mikro-orm/sqlite": "6.4.6", "@types/js-yaml": "^4.0.9", - "axios": "^1.8.1", + "axios": "^1.8.2", "dotenv": "^16.4.7", "express": "^5.0.1", "express-jwt": "^8.5.1", diff --git a/frontend/package.json b/frontend/package.json index 8c6f81d3..b056c9f3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -20,7 +20,7 @@ "vue-router": "^4.5.0", "vuetify": "^3.7.12", "oidc-client-ts": "^3.1.0", - "axios": "^1.8.1" + "axios": "^1.8.2" }, "devDependencies": { "@playwright/test": "^1.50.1", diff --git a/package-lock.json b/package-lock.json index 0efae7fc..e78b2d32 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,16 +34,16 @@ "@mikro-orm/sqlite": "6.4.6", "@types/cors": "^2.8.17", "@types/js-yaml": "^4.0.9", + "axios": "^1.8.2", "cors": "^2.8.5", - "axios": "^1.8.1", "dotenv": "^16.4.7", "express": "^5.0.1", "express-jwt": "^8.5.1", "js-yaml": "^4.1.0", "jwks-rsa": "^3.1.0", - "uuid": "^11.1.0", "loki-logger-ts": "^1.0.2", "response-time": "^2.3.3", + "uuid": "^11.1.0", "winston": "^3.17.0", "winston-loki": "^6.1.3" }, @@ -90,7 +90,7 @@ "name": "dwengo-1-frontend", "version": "0.0.1", "dependencies": { - "axios": "^1.8.1", + "axios": "^1.8.2", "oidc-client-ts": "^3.1.0", "vue": "^3.5.13", "vue-router": "^4.5.0", @@ -964,44 +964,6 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@intlify/core-base": { - "version": "10.0.5", - "license": "MIT", - "dependencies": { - "@intlify/message-compiler": "10.0.5", - "@intlify/shared": "10.0.5" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/kazupon" - } - }, - "node_modules/@intlify/message-compiler": { - "version": "10.0.5", - "license": "MIT", - "dependencies": { - "@intlify/shared": "10.0.5", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/kazupon" - } - }, - "node_modules/@intlify/shared": { - "version": "10.0.5", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/kazupon" - } - }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "dev": true, @@ -1660,7 +1622,6 @@ }, "node_modules/@types/body-parser": { "version": "1.19.5", - "dev": true, "license": "MIT", "dependencies": { "@types/connect": "*", @@ -1678,7 +1639,6 @@ "version": "2.8.17", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -1718,7 +1678,6 @@ }, "node_modules/@types/http-errors": { "version": "2.0.4", - "dev": true, "license": "MIT" }, "node_modules/@types/js-yaml": { @@ -1758,7 +1717,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "dev": true, "license": "MIT" }, "node_modules/@types/node": { @@ -1770,12 +1728,10 @@ }, "node_modules/@types/qs": { "version": "6.9.18", - "dev": true, "license": "MIT" }, "node_modules/@types/range-parser": { "version": "1.2.7", - "dev": true, "license": "MIT" }, "node_modules/@types/response-time": { @@ -1791,7 +1747,6 @@ }, "node_modules/@types/send": { "version": "0.17.4", - "dev": true, "license": "MIT", "dependencies": { "@types/mime": "^1", @@ -1800,7 +1755,6 @@ }, "node_modules/@types/serve-static": { "version": "1.15.7", - "dev": true, "license": "MIT", "dependencies": { "@types/http-errors": "*", @@ -2622,9 +2576,9 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.1.tgz", - "integrity": "sha512-NN+fvwH/kV01dYUQ3PTOZns4LWtWhOFCAhQ/pHb88WQ1hNe5V/dvFwc4VJcDL11LT9xSX0QtsR8sWUuyOuOq7g==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.2.tgz", + "integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -3123,7 +3077,6 @@ }, "node_modules/color-name": { "version": "1.1.4", - "dev": true, "license": "MIT" }, "node_modules/color-string": { @@ -5576,6 +5529,12 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, "node_modules/logform": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", @@ -5607,12 +5566,6 @@ "integrity": "sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng==", "license": "Apache-2.0" }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", - "license": "MIT" - }, "node_modules/loupe": { "version": "3.1.3", "dev": true, @@ -7909,14 +7862,6 @@ "node": ">=8" } }, - "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/strip-bom": { "version": "3.0.0", "dev": true, @@ -8855,24 +8800,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/vue-i18n": { - "version": "10.0.5", - "license": "MIT", - "dependencies": { - "@intlify/core-base": "10.0.5", - "@intlify/shared": "10.0.5", - "@vue/devtools-api": "^6.5.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/kazupon" - }, - "peerDependencies": { - "vue": "^3.0.0" - } - }, "node_modules/vue-router": { "version": "4.5.0", "license": "MIT", From da8e27acfdb2f96701c235471ea5d0e0ff17e59d Mon Sep 17 00:00:00 2001 From: Laure Jablonski Date: Mon, 10 Mar 2025 19:24:09 +0100 Subject: [PATCH 123/180] style: verander namen van variabelen zodat ze beginnen met een kleine letter --- backend/tests/data/answers.test.ts | 22 +++++------ backend/tests/data/assignments.test.ts | 22 +++++------ backend/tests/data/attachments.test.ts | 12 +++--- backend/tests/data/class-join-request.test.ts | 28 +++++++------- backend/tests/data/classes.test.ts | 12 +++--- backend/tests/data/groups.test.ts | 32 ++++++++-------- backend/tests/data/learning-objects.test.ts | 8 ++-- backend/tests/data/learning-paths.test.ts | 8 ++-- backend/tests/data/questions.test.ts | 18 ++++----- backend/tests/data/submissions.test.ts | 38 +++++++++---------- backend/tests/data/teacher-invitation.test.ts | 34 ++++++++--------- backend/tests/data/teachers.test.ts | 16 ++++---- 12 files changed, 125 insertions(+), 125 deletions(-) diff --git a/backend/tests/data/answers.test.ts b/backend/tests/data/answers.test.ts index 1757c475..54ffa592 100644 --- a/backend/tests/data/answers.test.ts +++ b/backend/tests/data/answers.test.ts @@ -13,21 +13,21 @@ import { Question } from '../../src/entities/questions/question.entity'; import { TeacherRepository } from '../../src/data/users/teacher-repository'; describe('AnswerRepository', () => { - let AnswerRepository: AnswerRepository; - let QuestionRepository: QuestionRepository; - let TeacherRepository: TeacherRepository; + let answerRepository: AnswerRepository; + let questionRepository: QuestionRepository; + let teacherRepository: TeacherRepository; beforeAll(async () => { await setupTestApp(); - AnswerRepository = getAnswerRepository(); - QuestionRepository = getQuestionRepository(); - TeacherRepository = getTeacherRepository(); + answerRepository = getAnswerRepository(); + questionRepository = getQuestionRepository(); + teacherRepository = getTeacherRepository(); }); it('should find all answers to a question', async () => { const id = new LearningObjectIdentifier('id05', Language.English, '1'); const questions = - await QuestionRepository.findAllQuestionsAboutLearningObject(id); + await questionRepository.findAllQuestionsAboutLearningObject(id); let question: Question; if (questions[0].sequenceNumber == 2) { question = questions[0]; @@ -35,7 +35,7 @@ describe('AnswerRepository', () => { question = questions[1]; } const answers = - await AnswerRepository.findAllAnswersToQuestion(question); + await answerRepository.findAllAnswersToQuestion(question); expect(answers).toBeTruthy(); expect(answers).toHaveLength(2); @@ -69,14 +69,14 @@ describe('AnswerRepository', () => { it('should not find a removed answer', async () => { const id = new LearningObjectIdentifier('id04', Language.English, '1'); const questions = - await QuestionRepository.findAllQuestionsAboutLearningObject(id); + await questionRepository.findAllQuestionsAboutLearningObject(id); - await AnswerRepository.removeAnswerByQuestionAndSequenceNumber( + await answerRepository.removeAnswerByQuestionAndSequenceNumber( questions[0], 1 ); - const emptyList = await AnswerRepository.findAllAnswersToQuestion( + const emptyList = await answerRepository.findAllAnswersToQuestion( questions[0] ); diff --git a/backend/tests/data/assignments.test.ts b/backend/tests/data/assignments.test.ts index 4494f19d..6ca520d8 100644 --- a/backend/tests/data/assignments.test.ts +++ b/backend/tests/data/assignments.test.ts @@ -8,18 +8,18 @@ import { import { ClassRepository } from '../../src/data/classes/class-repository'; describe('AssignmentRepository', () => { - let AssignmentRepository: AssignmentRepository; - let ClassRepository: ClassRepository; + let assignmentRepository: AssignmentRepository; + let classRepository: ClassRepository; beforeAll(async () => { await setupTestApp(); - AssignmentRepository = getAssignmentRepository(); - ClassRepository = getClassRepository(); + assignmentRepository = getAssignmentRepository(); + classRepository = getClassRepository(); }); it('should return the requested assignment', async () => { - const class_ = await ClassRepository.findById('id02'); - const assignment = await AssignmentRepository.findByClassAndId( + const class_ = await classRepository.findById('id02'); + const assignment = await assignmentRepository.findByClassAndId( class_!, 2 ); @@ -29,19 +29,19 @@ describe('AssignmentRepository', () => { }); it('should return all assignments for a class', async () => { - const class_ = await ClassRepository.findById('id02'); + const class_ = await classRepository.findById('id02'); const assignments = - await AssignmentRepository.findAllAssignmentsInClass(class_!); + await assignmentRepository.findAllAssignmentsInClass(class_!); expect(assignments).toBeTruthy(); expect(assignments).toHaveLength(1); }); it('should not find removed assignment', async () => { - const class_ = await ClassRepository.findById('id01'); - await AssignmentRepository.deleteByClassAndId(class_!, 3); + const class_ = await classRepository.findById('id01'); + await assignmentRepository.deleteByClassAndId(class_!, 3); - const assignment = await AssignmentRepository.findByClassAndId( + const assignment = await assignmentRepository.findByClassAndId( class_!, 3 ); diff --git a/backend/tests/data/attachments.test.ts b/backend/tests/data/attachments.test.ts index 5658fe67..82be74d9 100644 --- a/backend/tests/data/attachments.test.ts +++ b/backend/tests/data/attachments.test.ts @@ -10,22 +10,22 @@ import { LearningObjectIdentifier } from '../../src/entities/content/learning-ob import { Language } from '../../src/entities/content/language'; describe('AttachmentRepository', () => { - let AttachmentRepository: AttachmentRepository; - let LearningObjectRepository: LearningObjectRepository; + let attachmentRepository: AttachmentRepository; + let learningObjectRepository: LearningObjectRepository; beforeAll(async () => { await setupTestApp(); - AttachmentRepository = getAttachmentRepository(); - LearningObjectRepository = getLearningObjectRepository(); + attachmentRepository = getAttachmentRepository(); + learningObjectRepository = getLearningObjectRepository(); }); it('should return the requested attachment', async () => { const id = new LearningObjectIdentifier('id02', Language.English, '1'); const learningObject = - await LearningObjectRepository.findByIdentifier(id); + await learningObjectRepository.findByIdentifier(id); const attachment = - await AttachmentRepository.findByLearningObjectAndNumber( + await attachmentRepository.findByLearningObjectAndNumber( learningObject!, 1 ); diff --git a/backend/tests/data/class-join-request.test.ts b/backend/tests/data/class-join-request.test.ts index 4e966e45..771fdcdc 100644 --- a/backend/tests/data/class-join-request.test.ts +++ b/backend/tests/data/class-join-request.test.ts @@ -12,20 +12,20 @@ import { ClassRepository } from '../../src/data/classes/class-repository'; import { Student } from '../../src/entities/users/student.entity'; describe('ClassJoinRequestRepository', () => { - let ClassJoinRequestRepository: ClassJoinRequestRepository; - let StudentRepository: StudentRepository; - let ClassRepository: ClassRepository; + let classJoinRequestRepository: ClassJoinRequestRepository; + let studentRepository: StudentRepository; + let cassRepository: ClassRepository; beforeAll(async () => { await setupTestApp(); - ClassJoinRequestRepository = getClassJoinRequestRepository(); - StudentRepository = getStudentRepository(); - ClassRepository = getClassRepository(); + classJoinRequestRepository = getClassJoinRequestRepository(); + studentRepository = getStudentRepository(); + cassRepository = getClassRepository(); }); it('should list all requests from student to join classes', async () => { - const student = await StudentRepository.findByUsername('PinkFloyd'); - const requests = await ClassJoinRequestRepository.findAllRequestsBy( + const student = await studentRepository.findByUsername('PinkFloyd'); + const requests = await classJoinRequestRepository.findAllRequestsBy( student! ); @@ -34,8 +34,8 @@ describe('ClassJoinRequestRepository', () => { }); it('should list all requests to a single class', async () => { - const class_ = await ClassRepository.findById('id02'); - const requests = await ClassJoinRequestRepository.findAllOpenRequestsTo( + const class_ = await cassRepository.findById('id02'); + const requests = await classJoinRequestRepository.findAllOpenRequestsTo( class_! ); @@ -45,11 +45,11 @@ describe('ClassJoinRequestRepository', () => { it('should not find a removed request', async () => { const student = - await StudentRepository.findByUsername('SmashingPumpkins'); - const class_ = await ClassRepository.findById('id03'); - await ClassJoinRequestRepository.deleteBy(student!, class_!); + await studentRepository.findByUsername('SmashingPumpkins'); + const class_ = await cassRepository.findById('id03'); + await classJoinRequestRepository.deleteBy(student!, class_!); - const request = await ClassJoinRequestRepository.findAllRequestsBy( + const request = await classJoinRequestRepository.findAllRequestsBy( student! ); diff --git a/backend/tests/data/classes.test.ts b/backend/tests/data/classes.test.ts index dd4c4587..442cbd23 100644 --- a/backend/tests/data/classes.test.ts +++ b/backend/tests/data/classes.test.ts @@ -4,30 +4,30 @@ import { setupTestApp } from '../setup-tests'; import { getClassRepository } from '../../src/data/repositories'; describe('ClassRepository', () => { - let ClassRepository: ClassRepository; + let classRepository: ClassRepository; beforeAll(async () => { await setupTestApp(); - ClassRepository = getClassRepository(); + classRepository = getClassRepository(); }); it('should return nothing because id does not exist', async () => { - const classVar = await ClassRepository.findById('test_id'); + const classVar = await classRepository.findById('test_id'); expect(classVar).toBeNull(); }); it('should return requested class', async () => { - const classVar = await ClassRepository.findById('id01'); + const classVar = await classRepository.findById('id01'); expect(classVar).toBeTruthy(); expect(classVar?.displayName).toBe('class01'); }); it('class should be gone after deletion', async () => { - await ClassRepository.deleteById('id04'); + await classRepository.deleteById('id04'); - const classVar = await ClassRepository.findById('id04'); + const classVar = await classRepository.findById('id04'); expect(classVar).toBeNull(); }); diff --git a/backend/tests/data/groups.test.ts b/backend/tests/data/groups.test.ts index a181ecb5..a1e749f8 100644 --- a/backend/tests/data/groups.test.ts +++ b/backend/tests/data/groups.test.ts @@ -11,25 +11,25 @@ import { ClassRepository } from '../../src/data/classes/class-repository'; import { Class } from '../../src/entities/classes/class.entity'; describe('GroupRepository', () => { - let GroupRepository: GroupRepository; - let AssignmentRepository: AssignmentRepository; - let ClassRepository: ClassRepository; + let groupRepository: GroupRepository; + let assignmentRepository: AssignmentRepository; + let classRepository: ClassRepository; beforeAll(async () => { await setupTestApp(); - GroupRepository = getGroupRepository(); - AssignmentRepository = getAssignmentRepository(); - ClassRepository = getClassRepository(); + groupRepository = getGroupRepository(); + assignmentRepository = getAssignmentRepository(); + classRepository = getClassRepository(); }); it('should return the requested group', async () => { - const class_ = await ClassRepository.findById('id01'); - const assignment = await AssignmentRepository.findByClassAndId( + const class_ = await classRepository.findById('id01'); + const assignment = await assignmentRepository.findByClassAndId( class_!, 1 ); - const group = await GroupRepository.findByAssignmentAndGroupNumber( + const group = await groupRepository.findByAssignmentAndGroupNumber( assignment!, 1 ); @@ -38,13 +38,13 @@ describe('GroupRepository', () => { }); it('should return all groups for assignment', async () => { - const class_ = await ClassRepository.findById('id01'); - const assignment = await AssignmentRepository.findByClassAndId( + const class_ = await classRepository.findById('id01'); + const assignment = await assignmentRepository.findByClassAndId( class_!, 1 ); - const groups = await GroupRepository.findAllGroupsForAssignment( + const groups = await groupRepository.findAllGroupsForAssignment( assignment! ); @@ -53,15 +53,15 @@ describe('GroupRepository', () => { }); it('should not find removed group', async () => { - const class_ = await ClassRepository.findById('id02'); - const assignment = await AssignmentRepository.findByClassAndId( + const class_ = await classRepository.findById('id02'); + const assignment = await assignmentRepository.findByClassAndId( class_!, 2 ); - await GroupRepository.deleteByAssignmentAndGroupNumber(assignment!, 1); + await groupRepository.deleteByAssignmentAndGroupNumber(assignment!, 1); - const group = await GroupRepository.findByAssignmentAndGroupNumber( + const group = await groupRepository.findByAssignmentAndGroupNumber( assignment!, 1 ); diff --git a/backend/tests/data/learning-objects.test.ts b/backend/tests/data/learning-objects.test.ts index 65513b25..40a3adb7 100644 --- a/backend/tests/data/learning-objects.test.ts +++ b/backend/tests/data/learning-objects.test.ts @@ -6,11 +6,11 @@ import { LearningObjectIdentifier } from '../../src/entities/content/learning-ob import { Language } from '../../src/entities/content/language'; describe('LearningObjectRepository', () => { - let LearningObjectRepository: LearningObjectRepository; + let learningObjectRepository: LearningObjectRepository; beforeAll(async () => { await setupTestApp(); - LearningObjectRepository = getLearningObjectRepository(); + learningObjectRepository = getLearningObjectRepository(); }); const id01 = new LearningObjectIdentifier('id01', Language.English, '1'); @@ -18,7 +18,7 @@ describe('LearningObjectRepository', () => { it('should return the learning object that matches identifier 1', async () => { const learningObject = - await LearningObjectRepository.findByIdentifier(id01); + await learningObjectRepository.findByIdentifier(id01); expect(learningObject).toBeTruthy(); expect(learningObject?.title).toBe('Undertow'); @@ -27,7 +27,7 @@ describe('LearningObjectRepository', () => { it('should return nothing because the identifier does not exist in the database', async () => { const learningObject = - await LearningObjectRepository.findByIdentifier(id02); + await learningObjectRepository.findByIdentifier(id02); expect(learningObject).toBeNull(); }); diff --git a/backend/tests/data/learning-paths.test.ts b/backend/tests/data/learning-paths.test.ts index 70dad28a..9cd68ffe 100644 --- a/backend/tests/data/learning-paths.test.ts +++ b/backend/tests/data/learning-paths.test.ts @@ -5,16 +5,16 @@ import { setupTestApp } from '../setup-tests'; import { Language } from '../../src/entities/content/language'; describe('LearningPathRepository', () => { - let LearningPathRepository: LearningPathRepository; + let learningPathRepository: LearningPathRepository; beforeAll(async () => { await setupTestApp(); - LearningPathRepository = getLearningPathRepository(); + learningPathRepository = getLearningPathRepository(); }); it('should return nothing because no match for hruid and language', async () => { const learningPath = - await LearningPathRepository.findByHruidAndLanguage( + await learningPathRepository.findByHruidAndLanguage( 'test_id', Language.Dutch ); @@ -24,7 +24,7 @@ describe('LearningPathRepository', () => { it('should return requested learning path', async () => { const learningPath = - await LearningPathRepository.findByHruidAndLanguage( + await learningPathRepository.findByHruidAndLanguage( 'id01', Language.English ); diff --git a/backend/tests/data/questions.test.ts b/backend/tests/data/questions.test.ts index 41185d47..a516a97b 100644 --- a/backend/tests/data/questions.test.ts +++ b/backend/tests/data/questions.test.ts @@ -13,21 +13,21 @@ import { Language } from '../../src/entities/content/language'; import { Question } from '../../src/entities/questions/question.entity'; describe('QuestionRepository', () => { - let QuestionRepository: QuestionRepository; - let StudentRepository: StudentRepository; - let LearningObjectRepository: LearningObjectRepository; + let questionRepository: QuestionRepository; + let studentRepository: StudentRepository; + let learningObjectRepository: LearningObjectRepository; beforeAll(async () => { await setupTestApp(); - QuestionRepository = getQuestionRepository(); - StudentRepository = getStudentRepository(); - LearningObjectRepository = getLearningObjectRepository(); + questionRepository = getQuestionRepository(); + studentRepository = getStudentRepository(); + learningObjectRepository = getLearningObjectRepository(); }); it('should return all questions part of the given learning object', async () => { const id = new LearningObjectIdentifier('id05', Language.English, '1'); const questions = - await QuestionRepository.findAllQuestionsAboutLearningObject(id); + await questionRepository.findAllQuestionsAboutLearningObject(id); expect(questions).toBeTruthy(); expect(questions).toHaveLength(2); @@ -50,13 +50,13 @@ describe('QuestionRepository', () => { it('should not find removed question', async () => { const id = new LearningObjectIdentifier('id04', Language.English, '1'); - await QuestionRepository.removeQuestionByLearningObjectAndSequenceNumber( + await questionRepository.removeQuestionByLearningObjectAndSequenceNumber( id, 1 ); const question = - await QuestionRepository.findAllQuestionsAboutLearningObject(id); + await questionRepository.findAllQuestionsAboutLearningObject(id); expect(question).toHaveLength(0); }); diff --git a/backend/tests/data/submissions.test.ts b/backend/tests/data/submissions.test.ts index 5eb2b11a..3c7265b8 100644 --- a/backend/tests/data/submissions.test.ts +++ b/backend/tests/data/submissions.test.ts @@ -19,25 +19,25 @@ import { AssignmentRepository } from '../../src/data/assignments/assignment-repo import { ClassRepository } from '../../src/data/classes/class-repository'; describe('SubmissionRepository', () => { - let SubmissionRepository: SubmissionRepository; - let StudentRepository: StudentRepository; - let GroupRepository: GroupRepository; - let AssignmentRepository: AssignmentRepository; - let ClassRepository: ClassRepository; + let submissionRepository: SubmissionRepository; + let studentRepository: StudentRepository; + let groupRepository: GroupRepository; + let assignmentRepository: AssignmentRepository; + let classRepository: ClassRepository; beforeAll(async () => { await setupTestApp(); - SubmissionRepository = getSubmissionRepository(); - StudentRepository = getStudentRepository(); - GroupRepository = getGroupRepository(); - AssignmentRepository = getAssignmentRepository(); - ClassRepository = getClassRepository(); + submissionRepository = getSubmissionRepository(); + studentRepository = getStudentRepository(); + groupRepository = getGroupRepository(); + assignmentRepository = getAssignmentRepository(); + classRepository = getClassRepository(); }); it('should find the requested submission', async () => { const id = new LearningObjectIdentifier('id03', Language.English, '1'); const submission = - await SubmissionRepository.findSubmissionByLearningObjectAndSubmissionNumber( + await submissionRepository.findSubmissionByLearningObjectAndSubmissionNumber( id, 1 ); @@ -48,9 +48,9 @@ describe('SubmissionRepository', () => { it('should find the most recent submission for a student', async () => { const id = new LearningObjectIdentifier('id02', Language.English, '1'); - const student = await StudentRepository.findByUsername('Noordkaap'); + const student = await studentRepository.findByUsername('Noordkaap'); const submission = - await SubmissionRepository.findMostRecentSubmissionForStudent( + await submissionRepository.findMostRecentSubmissionForStudent( id, student! ); @@ -61,17 +61,17 @@ describe('SubmissionRepository', () => { it('should find the most recent submission for a group', async () => { const id = new LearningObjectIdentifier('id03', Language.English, '1'); - const class_ = await ClassRepository.findById('id01'); - const assignment = await AssignmentRepository.findByClassAndId( + const class_ = await classRepository.findById('id01'); + const assignment = await assignmentRepository.findByClassAndId( class_!, 1 ); - const group = await GroupRepository.findByAssignmentAndGroupNumber( + const group = await groupRepository.findByAssignmentAndGroupNumber( assignment!, 1 ); const submission = - await SubmissionRepository.findMostRecentSubmissionForGroup( + await submissionRepository.findMostRecentSubmissionForGroup( id, group! ); @@ -82,13 +82,13 @@ describe('SubmissionRepository', () => { it('should not find a deleted submission', async () => { const id = new LearningObjectIdentifier('id01', Language.English, '1'); - await SubmissionRepository.deleteSubmissionByLearningObjectAndSubmissionNumber( + await submissionRepository.deleteSubmissionByLearningObjectAndSubmissionNumber( id, 1 ); const submission = - await SubmissionRepository.findSubmissionByLearningObjectAndSubmissionNumber( + await submissionRepository.findSubmissionByLearningObjectAndSubmissionNumber( id, 1 ); diff --git a/backend/tests/data/teacher-invitation.test.ts b/backend/tests/data/teacher-invitation.test.ts index e075ee46..9fe5712f 100644 --- a/backend/tests/data/teacher-invitation.test.ts +++ b/backend/tests/data/teacher-invitation.test.ts @@ -10,39 +10,39 @@ import { TeacherRepository } from '../../src/data/users/teacher-repository'; import { ClassRepository } from '../../src/data/classes/class-repository'; describe('ClassRepository', () => { - let TeacherInvitationRepository: TeacherInvitationRepository; - let TeacherRepository: TeacherRepository; - let ClassRepository: ClassRepository; + let teacherInvitationRepository: TeacherInvitationRepository; + let teacherRepository: TeacherRepository; + let classRepository: ClassRepository; beforeAll(async () => { await setupTestApp(); - TeacherInvitationRepository = getTeacherInvitationRepository(); - TeacherRepository = getTeacherRepository(); - ClassRepository = getClassRepository(); + teacherInvitationRepository = getTeacherInvitationRepository(); + teacherRepository = getTeacherRepository(); + classRepository = getClassRepository(); }); it('should return all invitations from a teacher', async () => { - const teacher = await TeacherRepository.findByUsername('LimpBizkit'); + const teacher = await teacherRepository.findByUsername('LimpBizkit'); const invitations = - await TeacherInvitationRepository.findAllInvitationsBy(teacher!); + await teacherInvitationRepository.findAllInvitationsBy(teacher!); expect(invitations).toBeTruthy(); expect(invitations).toHaveLength(2); }); it('should return all invitations for a teacher', async () => { - const teacher = await TeacherRepository.findByUsername('FooFighters'); + const teacher = await teacherRepository.findByUsername('FooFighters'); const invitations = - await TeacherInvitationRepository.findAllInvitationsFor(teacher!); + await teacherInvitationRepository.findAllInvitationsFor(teacher!); expect(invitations).toBeTruthy(); expect(invitations).toHaveLength(2); }); it('should return all invitations for a class', async () => { - const class_ = await ClassRepository.findById('id02'); + const class_ = await classRepository.findById('id02'); const invitations = - await TeacherInvitationRepository.findAllInvitationsForClass( + await teacherInvitationRepository.findAllInvitationsForClass( class_! ); @@ -51,13 +51,13 @@ describe('ClassRepository', () => { }); it('should not find a removed invitation', async () => { - const class_ = await ClassRepository.findById('id01'); - const sender = await TeacherRepository.findByUsername('FooFighters'); - const receiver = await TeacherRepository.findByUsername('LimpBizkit'); - await TeacherInvitationRepository.deleteBy(class_!, sender!, receiver!); + const class_ = await classRepository.findById('id01'); + const sender = await teacherRepository.findByUsername('FooFighters'); + const receiver = await teacherRepository.findByUsername('LimpBizkit'); + await teacherInvitationRepository.deleteBy(class_!, sender!, receiver!); const invitation = - await TeacherInvitationRepository.findAllInvitationsBy(sender!); + await teacherInvitationRepository.findAllInvitationsBy(sender!); expect(invitation).toHaveLength(0); }); diff --git a/backend/tests/data/teachers.test.ts b/backend/tests/data/teachers.test.ts index 289079d4..eba34946 100644 --- a/backend/tests/data/teachers.test.ts +++ b/backend/tests/data/teachers.test.ts @@ -8,21 +8,21 @@ const username = 'testteacher'; const firstName = 'John'; const lastName = 'Doe'; describe('TeacherRepository', () => { - let TeacherRepository: TeacherRepository; + let teacherRepository: TeacherRepository; beforeAll(async () => { await setupTestApp(); - TeacherRepository = getTeacherRepository(); + teacherRepository = getTeacherRepository(); }); it('should not return a teacher because username does not exist', async () => { - const teacher = await TeacherRepository.findByUsername('test'); + const teacher = await teacherRepository.findByUsername('test'); expect(teacher).toBeNull(); }); it('should return teacher from the datbase', async () => { - const teacher = await TeacherRepository.findByUsername('FooFighters'); + const teacher = await teacherRepository.findByUsername('FooFighters'); expect(teacher).toBeTruthy(); expect(teacher?.firstName).toBe('Dave'); @@ -30,22 +30,22 @@ describe('TeacherRepository', () => { }); it('should return the queried teacher after he was added', async () => { - await TeacherRepository.insert( + await teacherRepository.insert( new Teacher(username, firstName, lastName) ); const retrievedTeacher = - await TeacherRepository.findByUsername(username); + await teacherRepository.findByUsername(username); expect(retrievedTeacher).toBeTruthy(); expect(retrievedTeacher?.firstName).toBe(firstName); expect(retrievedTeacher?.lastName).toBe(lastName); }); it('should no longer return the queried teacher after he was removed again', async () => { - await TeacherRepository.deleteByUsername('ZesdeMetaal'); + await teacherRepository.deleteByUsername('ZesdeMetaal'); const retrievedTeacher = - await TeacherRepository.findByUsername('ZesdeMetaal'); + await teacherRepository.findByUsername('ZesdeMetaal'); expect(retrievedTeacher).toBeNull(); }); }); From 946c233a529010d4c28a9536094376b49c865eb6 Mon Sep 17 00:00:00 2001 From: Laure Jablonski Date: Mon, 10 Mar 2025 19:36:19 +0100 Subject: [PATCH 124/180] test: de antwoorden die teruggegeven worden zijn de juiste --- backend/tests/data/answers.test.ts | 28 ++++++++++++---------------- backend/tests/setup-tests.ts | 2 +- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/backend/tests/data/answers.test.ts b/backend/tests/data/answers.test.ts index 54ffa592..52956b6e 100644 --- a/backend/tests/data/answers.test.ts +++ b/backend/tests/data/answers.test.ts @@ -28,38 +28,34 @@ describe('AnswerRepository', () => { const id = new LearningObjectIdentifier('id05', Language.English, '1'); const questions = await questionRepository.findAllQuestionsAboutLearningObject(id); - let question: Question; - if (questions[0].sequenceNumber == 2) { - question = questions[0]; - } else { - question = questions[1]; - } + + const question = questions.filter((it) => it.sequenceNumber == 2)[0]; + const answers = await answerRepository.findAllAnswersToQuestion(question); expect(answers).toBeTruthy(); expect(answers).toHaveLength(2); + expect(answers[0].content).toBeOneOf(['answer', 'answer2']); + expect(answers[1].content).toBeOneOf(['answer', 'answer2']); }); // it('should create an answer to a question', async () => { - // const teacher = await TeacherRepository.findByUsername('FooFighters'); + // const teacher = await teacherRepository.findByUsername('FooFighters'); // const id = new LearningObjectIdentifier('id05', Language.English, '1'); // const questions = - // await QuestionRepository.findAllQuestionsAboutLearningObject(id); - // let question: Question; - // if (questions[0].sequenceNumber == 1) { - // question = questions[0]; - // } else { - // question = questions[1]; - // } - // await AnswerRepository.createAnswer({ + // await questionRepository.findAllQuestionsAboutLearningObject(id); + + // const question = questions[0]; + + // await answerRepository.createAnswer({ // toQuestion: question, // author: teacher!, // content: 'created answer', // }); // const answers = - // await AnswerRepository.findAllAnswersToQuestion(question); + // await answerRepository.findAllAnswersToQuestion(question); // expect(answers).toBeTruthy(); // expect(answers).toHaveLength(1); diff --git a/backend/tests/setup-tests.ts b/backend/tests/setup-tests.ts index 2f497ece..92e886bf 100644 --- a/backend/tests/setup-tests.ts +++ b/backend/tests/setup-tests.ts @@ -537,7 +537,7 @@ export async function setupTestApp() { toQuestion: question04, sequenceNumber: 1, timestamp: new Date(), - content: 'answer', + content: 'answer3', }); const submission01 = em.create(Submission, { From 5f55da987c9dae9172bfb7b33fc6444e8bb223cb Mon Sep 17 00:00:00 2001 From: Laure Jablonski Date: Mon, 10 Mar 2025 19:39:56 +0100 Subject: [PATCH 125/180] test: teruggeven assignments zijn de juiste --- backend/tests/data/assignments.test.ts | 1 + backend/tests/data/questions.test.ts | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/backend/tests/data/assignments.test.ts b/backend/tests/data/assignments.test.ts index 6ca520d8..1048ce95 100644 --- a/backend/tests/data/assignments.test.ts +++ b/backend/tests/data/assignments.test.ts @@ -35,6 +35,7 @@ describe('AssignmentRepository', () => { expect(assignments).toBeTruthy(); expect(assignments).toHaveLength(1); + expect(assignments[0].title).toBe('tool'); }); it('should not find removed assignment', async () => { diff --git a/backend/tests/data/questions.test.ts b/backend/tests/data/questions.test.ts index a516a97b..0060b996 100644 --- a/backend/tests/data/questions.test.ts +++ b/backend/tests/data/questions.test.ts @@ -35,14 +35,14 @@ describe('QuestionRepository', () => { // it('should create new question', async () => { // const id = new LearningObjectIdentifier('id03', Language.English, '1'); - // const student = await StudentRepository.findByUsername('Noordkaap'); - // await QuestionRepository.createQuestion({ + // const student = await studentRepository.findByUsername('Noordkaap'); + // await questionRepository.createQuestion({ // loId: id, // author: student!, // content: 'question?', // }); // const question = - // await QuestionRepository.findAllQuestionsAboutLearningObject(id); + // await questionRepository.findAllQuestionsAboutLearningObject(id); // expect(question).toBeTruthy(); // expect(question).toHaveLength(1); From 678ced55ba36d3bbb5c93c5b470e8e3920a2bbc7 Mon Sep 17 00:00:00 2001 From: Laure Jablonski Date: Mon, 10 Mar 2025 21:01:09 +0100 Subject: [PATCH 126/180] style: verander de structuur van de testmap --- .../{ => assignments}/assignments.test.ts | 8 +- .../data/{ => assignments}/groups.test.ts | 11 +- .../{ => assignments}/submissions.test.ts | 21 +- .../{ => classes}/class-join-request.test.ts | 14 +- .../tests/data/{ => classes}/classes.test.ts | 6 +- .../{ => classes}/teacher-invitation.test.ts | 10 +- .../data/{ => content}/attachments.test.ts | 12 +- .../{ => content}/learning-objects.test.ts | 10 +- .../data/{ => content}/learning-paths.test.ts | 8 +- .../data/{ => questions}/answers.test.ts | 16 +- .../data/{ => questions}/questions.test.ts | 16 +- .../tests/data/{ => users}/students.test.ts | 8 +- .../tests/data/{ => users}/teachers.test.ts | 8 +- backend/tests/setup-tests.ts | 676 ++---------------- .../assignments/assignments.testdata.ts | 41 ++ .../assignments/groups.testdata.ts | 36 + .../assignments/submission.testdata.ts | 71 ++ .../classes/class-join-requests.testdata.ts | 44 ++ .../test_assets/classes/classes.testdata.ts | 54 ++ .../classes/teacher-invitations.testdata.ts | 41 ++ .../content/attachments.testdata.ts | 17 + .../content/learning-objects.testdata.ts | 149 ++++ .../content/learning-paths.testdata.ts | 104 +++ .../test_assets/questions/answers.testdata.ts | 36 + .../questions/questions.testdata.ts | 51 ++ .../test_assets/users/students.testdata.ts | 59 ++ .../test_assets/users/teachers.testdata.ts | 33 + 27 files changed, 854 insertions(+), 706 deletions(-) rename backend/tests/data/{ => assignments}/assignments.test.ts (85%) rename backend/tests/data/{ => assignments}/groups.test.ts (82%) rename backend/tests/data/{ => assignments}/submissions.test.ts (77%) rename backend/tests/data/{ => classes}/class-join-request.test.ts (77%) rename backend/tests/data/{ => classes}/classes.test.ts (81%) rename backend/tests/data/{ => classes}/teacher-invitation.test.ts (86%) rename backend/tests/data/{ => content}/attachments.test.ts (67%) rename backend/tests/data/{ => content}/learning-objects.test.ts (73%) rename backend/tests/data/{ => content}/learning-paths.test.ts (77%) rename backend/tests/data/{ => questions}/answers.test.ts (81%) rename backend/tests/data/{ => questions}/questions.test.ts (76%) rename backend/tests/data/{ => users}/students.test.ts (84%) rename backend/tests/data/{ => users}/teachers.test.ts (85%) create mode 100644 backend/tests/test_assets/assignments/assignments.testdata.ts create mode 100644 backend/tests/test_assets/assignments/groups.testdata.ts create mode 100644 backend/tests/test_assets/assignments/submission.testdata.ts create mode 100644 backend/tests/test_assets/classes/class-join-requests.testdata.ts create mode 100644 backend/tests/test_assets/classes/classes.testdata.ts create mode 100644 backend/tests/test_assets/classes/teacher-invitations.testdata.ts create mode 100644 backend/tests/test_assets/content/attachments.testdata.ts create mode 100644 backend/tests/test_assets/content/learning-objects.testdata.ts create mode 100644 backend/tests/test_assets/content/learning-paths.testdata.ts create mode 100644 backend/tests/test_assets/questions/answers.testdata.ts create mode 100644 backend/tests/test_assets/questions/questions.testdata.ts create mode 100644 backend/tests/test_assets/users/students.testdata.ts create mode 100644 backend/tests/test_assets/users/teachers.testdata.ts diff --git a/backend/tests/data/assignments.test.ts b/backend/tests/data/assignments/assignments.test.ts similarity index 85% rename from backend/tests/data/assignments.test.ts rename to backend/tests/data/assignments/assignments.test.ts index 1048ce95..d091722f 100644 --- a/backend/tests/data/assignments.test.ts +++ b/backend/tests/data/assignments/assignments.test.ts @@ -1,11 +1,11 @@ import { beforeAll, describe, expect, it } from 'vitest'; -import { setupTestApp } from '../setup-tests'; -import { AssignmentRepository } from '../../src/data/assignments/assignment-repository'; +import { setupTestApp } from '../../setup-tests'; +import { AssignmentRepository } from '../../../src/data/assignments/assignment-repository'; import { getAssignmentRepository, getClassRepository, -} from '../../src/data/repositories'; -import { ClassRepository } from '../../src/data/classes/class-repository'; +} from '../../../src/data/repositories'; +import { ClassRepository } from '../../../src/data/classes/class-repository'; describe('AssignmentRepository', () => { let assignmentRepository: AssignmentRepository; diff --git a/backend/tests/data/groups.test.ts b/backend/tests/data/assignments/groups.test.ts similarity index 82% rename from backend/tests/data/groups.test.ts rename to backend/tests/data/assignments/groups.test.ts index a1e749f8..d82f7e1f 100644 --- a/backend/tests/data/groups.test.ts +++ b/backend/tests/data/assignments/groups.test.ts @@ -1,14 +1,13 @@ import { beforeAll, describe, expect, it } from 'vitest'; -import { setupTestApp } from '../setup-tests'; -import { GroupRepository } from '../../src/data/assignments/group-repository'; +import { setupTestApp } from '../../setup-tests'; +import { GroupRepository } from '../../../src/data/assignments/group-repository'; import { getAssignmentRepository, getClassRepository, getGroupRepository, -} from '../../src/data/repositories'; -import { AssignmentRepository } from '../../src/data/assignments/assignment-repository'; -import { ClassRepository } from '../../src/data/classes/class-repository'; -import { Class } from '../../src/entities/classes/class.entity'; +} from '../../../src/data/repositories'; +import { AssignmentRepository } from '../../../src/data/assignments/assignment-repository'; +import { ClassRepository } from '../../../src/data/classes/class-repository'; describe('GroupRepository', () => { let groupRepository: GroupRepository; diff --git a/backend/tests/data/submissions.test.ts b/backend/tests/data/assignments/submissions.test.ts similarity index 77% rename from backend/tests/data/submissions.test.ts rename to backend/tests/data/assignments/submissions.test.ts index 3c7265b8..16b74a32 100644 --- a/backend/tests/data/submissions.test.ts +++ b/backend/tests/data/assignments/submissions.test.ts @@ -1,22 +1,19 @@ import { beforeAll, describe, expect, it } from 'vitest'; -import { setupTestApp } from '../setup-tests'; -import { SubmissionRepository } from '../../src/data/assignments/submission-repository'; +import { setupTestApp } from '../../setup-tests'; +import { SubmissionRepository } from '../../../src/data/assignments/submission-repository'; import { getAssignmentRepository, getClassRepository, getGroupRepository, getStudentRepository, getSubmissionRepository, -} from '../../src/data/repositories'; -import { LearningObject } from '../../src/entities/content/learning-object.entity'; -import { LearningObjectIdentifier } from '../../src/entities/content/learning-object-identifier'; -import { Language } from '../../src/entities/content/language'; -import { subscribe } from 'diagnostics_channel'; -import { Student } from '../../src/entities/users/student.entity'; -import { StudentRepository } from '../../src/data/users/student-repository'; -import { GroupRepository } from '../../src/data/assignments/group-repository'; -import { AssignmentRepository } from '../../src/data/assignments/assignment-repository'; -import { ClassRepository } from '../../src/data/classes/class-repository'; +} from '../../../src/data/repositories'; +import { LearningObjectIdentifier } from '../../../src/entities/content/learning-object-identifier'; +import { Language } from '../../../src/entities/content/language'; +import { StudentRepository } from '../../../src/data/users/student-repository'; +import { GroupRepository } from '../../../src/data/assignments/group-repository'; +import { AssignmentRepository } from '../../../src/data/assignments/assignment-repository'; +import { ClassRepository } from '../../../src/data/classes/class-repository'; describe('SubmissionRepository', () => { let submissionRepository: SubmissionRepository; diff --git a/backend/tests/data/class-join-request.test.ts b/backend/tests/data/classes/class-join-request.test.ts similarity index 77% rename from backend/tests/data/class-join-request.test.ts rename to backend/tests/data/classes/class-join-request.test.ts index 771fdcdc..23aabcb6 100644 --- a/backend/tests/data/class-join-request.test.ts +++ b/backend/tests/data/classes/class-join-request.test.ts @@ -1,15 +1,15 @@ import { beforeAll, describe, expect, it } from 'vitest'; -import { setupTestApp } from '../setup-tests'; -import { ClassJoinRequestRepository } from '../../src/data/classes/class-join-request-repository'; +import { setupTestApp } from '../../setup-tests'; +import { ClassJoinRequestRepository } from '../../../src/data/classes/class-join-request-repository'; import { getClassJoinRequestRepository, getClassRepository, getStudentRepository, -} from '../../src/data/repositories'; -import { StudentRepository } from '../../src/data/users/student-repository'; -import { Class } from '../../src/entities/classes/class.entity'; -import { ClassRepository } from '../../src/data/classes/class-repository'; -import { Student } from '../../src/entities/users/student.entity'; +} from '../../../src/data/repositories'; +import { StudentRepository } from '../../../src/data/users/student-repository'; +import { Class } from '../../../src/entities/classes/class.entity'; +import { ClassRepository } from '../../../src/data/classes/class-repository'; +import { Student } from '../../../src/entities/users/student.entity'; describe('ClassJoinRequestRepository', () => { let classJoinRequestRepository: ClassJoinRequestRepository; diff --git a/backend/tests/data/classes.test.ts b/backend/tests/data/classes/classes.test.ts similarity index 81% rename from backend/tests/data/classes.test.ts rename to backend/tests/data/classes/classes.test.ts index 442cbd23..22306ba6 100644 --- a/backend/tests/data/classes.test.ts +++ b/backend/tests/data/classes/classes.test.ts @@ -1,7 +1,7 @@ import { beforeAll, describe, expect, it } from 'vitest'; -import { ClassRepository } from '../../src/data/classes/class-repository'; -import { setupTestApp } from '../setup-tests'; -import { getClassRepository } from '../../src/data/repositories'; +import { ClassRepository } from '../../../src/data/classes/class-repository'; +import { setupTestApp } from '../../setup-tests'; +import { getClassRepository } from '../../../src/data/repositories'; describe('ClassRepository', () => { let classRepository: ClassRepository; diff --git a/backend/tests/data/teacher-invitation.test.ts b/backend/tests/data/classes/teacher-invitation.test.ts similarity index 86% rename from backend/tests/data/teacher-invitation.test.ts rename to backend/tests/data/classes/teacher-invitation.test.ts index 9fe5712f..f5257286 100644 --- a/backend/tests/data/teacher-invitation.test.ts +++ b/backend/tests/data/classes/teacher-invitation.test.ts @@ -1,13 +1,13 @@ import { beforeAll, describe, expect, it } from 'vitest'; -import { setupTestApp } from '../setup-tests'; +import { setupTestApp } from '../../setup-tests'; import { getClassRepository, getTeacherInvitationRepository, getTeacherRepository, -} from '../../src/data/repositories'; -import { TeacherInvitationRepository } from '../../src/data/classes/teacher-invitation-repository'; -import { TeacherRepository } from '../../src/data/users/teacher-repository'; -import { ClassRepository } from '../../src/data/classes/class-repository'; +} from '../../../src/data/repositories'; +import { TeacherInvitationRepository } from '../../../src/data/classes/teacher-invitation-repository'; +import { TeacherRepository } from '../../../src/data/users/teacher-repository'; +import { ClassRepository } from '../../../src/data/classes/class-repository'; describe('ClassRepository', () => { let teacherInvitationRepository: TeacherInvitationRepository; diff --git a/backend/tests/data/attachments.test.ts b/backend/tests/data/content/attachments.test.ts similarity index 67% rename from backend/tests/data/attachments.test.ts rename to backend/tests/data/content/attachments.test.ts index 82be74d9..a5a3d35f 100644 --- a/backend/tests/data/attachments.test.ts +++ b/backend/tests/data/content/attachments.test.ts @@ -1,13 +1,13 @@ import { beforeAll, describe, expect, it } from 'vitest'; -import { setupTestApp } from '../setup-tests'; +import { setupTestApp } from '../../setup-tests'; import { getAttachmentRepository, getLearningObjectRepository, -} from '../../src/data/repositories'; -import { AttachmentRepository } from '../../src/data/content/attachment-repository'; -import { LearningObjectRepository } from '../../src/data/content/learning-object-repository'; -import { LearningObjectIdentifier } from '../../src/entities/content/learning-object-identifier'; -import { Language } from '../../src/entities/content/language'; +} from '../../../src/data/repositories'; +import { AttachmentRepository } from '../../../src/data/content/attachment-repository'; +import { LearningObjectRepository } from '../../../src/data/content/learning-object-repository'; +import { LearningObjectIdentifier } from '../../../src/entities/content/learning-object-identifier'; +import { Language } from '../../../src/entities/content/language'; describe('AttachmentRepository', () => { let attachmentRepository: AttachmentRepository; diff --git a/backend/tests/data/learning-objects.test.ts b/backend/tests/data/content/learning-objects.test.ts similarity index 73% rename from backend/tests/data/learning-objects.test.ts rename to backend/tests/data/content/learning-objects.test.ts index 40a3adb7..629aa318 100644 --- a/backend/tests/data/learning-objects.test.ts +++ b/backend/tests/data/content/learning-objects.test.ts @@ -1,9 +1,9 @@ import { beforeAll, describe, expect, it } from 'vitest'; -import { LearningObjectRepository } from '../../src/data/content/learning-object-repository'; -import { getLearningObjectRepository } from '../../src/data/repositories'; -import { setupTestApp } from '../setup-tests'; -import { LearningObjectIdentifier } from '../../src/entities/content/learning-object-identifier'; -import { Language } from '../../src/entities/content/language'; +import { LearningObjectRepository } from '../../../src/data/content/learning-object-repository'; +import { getLearningObjectRepository } from '../../../src/data/repositories'; +import { setupTestApp } from '../../setup-tests'; +import { LearningObjectIdentifier } from '../../../src/entities/content/learning-object-identifier'; +import { Language } from '../../../src/entities/content/language'; describe('LearningObjectRepository', () => { let learningObjectRepository: LearningObjectRepository; diff --git a/backend/tests/data/learning-paths.test.ts b/backend/tests/data/content/learning-paths.test.ts similarity index 77% rename from backend/tests/data/learning-paths.test.ts rename to backend/tests/data/content/learning-paths.test.ts index 9cd68ffe..984fd995 100644 --- a/backend/tests/data/learning-paths.test.ts +++ b/backend/tests/data/content/learning-paths.test.ts @@ -1,8 +1,8 @@ import { beforeAll, describe, expect, it } from 'vitest'; -import { getLearningPathRepository } from '../../src/data/repositories'; -import { LearningPathRepository } from '../../src/data/content/learning-path-repository'; -import { setupTestApp } from '../setup-tests'; -import { Language } from '../../src/entities/content/language'; +import { getLearningPathRepository } from '../../../src/data/repositories'; +import { LearningPathRepository } from '../../../src/data/content/learning-path-repository'; +import { setupTestApp } from '../../setup-tests'; +import { Language } from '../../../src/entities/content/language'; describe('LearningPathRepository', () => { let learningPathRepository: LearningPathRepository; diff --git a/backend/tests/data/answers.test.ts b/backend/tests/data/questions/answers.test.ts similarity index 81% rename from backend/tests/data/answers.test.ts rename to backend/tests/data/questions/answers.test.ts index 52956b6e..6ee63d2e 100644 --- a/backend/tests/data/answers.test.ts +++ b/backend/tests/data/questions/answers.test.ts @@ -1,16 +1,16 @@ import { beforeAll, describe, expect, it } from 'vitest'; -import { setupTestApp } from '../setup-tests'; -import { AnswerRepository } from '../../src/data/questions/answer-repository'; +import { setupTestApp } from '../../setup-tests'; +import { AnswerRepository } from '../../../src/data/questions/answer-repository'; import { getAnswerRepository, getQuestionRepository, getTeacherRepository, -} from '../../src/data/repositories'; -import { QuestionRepository } from '../../src/data/questions/question-repository'; -import { LearningObjectIdentifier } from '../../src/entities/content/learning-object-identifier'; -import { Language } from '../../src/entities/content/language'; -import { Question } from '../../src/entities/questions/question.entity'; -import { TeacherRepository } from '../../src/data/users/teacher-repository'; +} from '../../../src/data/repositories'; +import { QuestionRepository } from '../../../src/data/questions/question-repository'; +import { LearningObjectIdentifier } from '../../../src/entities/content/learning-object-identifier'; +import { Language } from '../../../src/entities/content/language'; +import { Question } from '../../../src/entities/questions/question.entity'; +import { TeacherRepository } from '../../../src/data/users/teacher-repository'; describe('AnswerRepository', () => { let answerRepository: AnswerRepository; diff --git a/backend/tests/data/questions.test.ts b/backend/tests/data/questions/questions.test.ts similarity index 76% rename from backend/tests/data/questions.test.ts rename to backend/tests/data/questions/questions.test.ts index 0060b996..ad47e5b3 100644 --- a/backend/tests/data/questions.test.ts +++ b/backend/tests/data/questions/questions.test.ts @@ -1,16 +1,16 @@ import { beforeAll, describe, expect, it } from 'vitest'; -import { setupTestApp } from '../setup-tests'; -import { QuestionRepository } from '../../src/data/questions/question-repository'; +import { setupTestApp } from '../../setup-tests'; +import { QuestionRepository } from '../../../src/data/questions/question-repository'; import { getLearningObjectRepository, getQuestionRepository, getStudentRepository, -} from '../../src/data/repositories'; -import { StudentRepository } from '../../src/data/users/student-repository'; -import { LearningObjectRepository } from '../../src/data/content/learning-object-repository'; -import { LearningObjectIdentifier } from '../../src/entities/content/learning-object-identifier'; -import { Language } from '../../src/entities/content/language'; -import { Question } from '../../src/entities/questions/question.entity'; +} from '../../../src/data/repositories'; +import { StudentRepository } from '../../../src/data/users/student-repository'; +import { LearningObjectRepository } from '../../../src/data/content/learning-object-repository'; +import { LearningObjectIdentifier } from '../../../src/entities/content/learning-object-identifier'; +import { Language } from '../../../src/entities/content/language'; +import { Question } from '../../../src/entities/questions/question.entity'; describe('QuestionRepository', () => { let questionRepository: QuestionRepository; diff --git a/backend/tests/data/students.test.ts b/backend/tests/data/users/students.test.ts similarity index 84% rename from backend/tests/data/students.test.ts rename to backend/tests/data/users/students.test.ts index ce1ee586..9fa52819 100644 --- a/backend/tests/data/students.test.ts +++ b/backend/tests/data/users/students.test.ts @@ -1,8 +1,8 @@ -import { setupTestApp } from '../setup-tests.js'; -import { Student } from '../../src/entities/users/student.entity.js'; +import { setupTestApp } from '../../setup-tests.js'; +import { Student } from '../../../src/entities/users/student.entity.js'; import { describe, it, expect, beforeAll } from 'vitest'; -import { StudentRepository } from '../../src/data/users/student-repository.js'; -import { getStudentRepository } from '../../src/data/repositories.js'; +import { StudentRepository } from '../../../src/data/users/student-repository.js'; +import { getStudentRepository } from '../../../src/data/repositories.js'; const username = 'teststudent'; const firstName = 'John'; diff --git a/backend/tests/data/teachers.test.ts b/backend/tests/data/users/teachers.test.ts similarity index 85% rename from backend/tests/data/teachers.test.ts rename to backend/tests/data/users/teachers.test.ts index eba34946..5aa69907 100644 --- a/backend/tests/data/teachers.test.ts +++ b/backend/tests/data/users/teachers.test.ts @@ -1,8 +1,8 @@ -import { setupTestApp } from '../setup-tests.js'; import { describe, it, expect, beforeAll } from 'vitest'; -import { TeacherRepository } from '../../src/data/users/teacher-repository.js'; -import { Teacher } from '../../src/entities/users/teacher.entity.js'; -import { getTeacherRepository } from '../../src/data/repositories.js'; +import { TeacherRepository } from '../../../src/data/users/teacher-repository'; +import { setupTestApp } from '../../setup-tests'; +import { getTeacherRepository } from '../../../src/data/repositories'; +import { Teacher } from '../../../src/entities/users/teacher.entity'; const username = 'testteacher'; const firstName = 'John'; diff --git a/backend/tests/setup-tests.ts b/backend/tests/setup-tests.ts index 92e886bf..5f1bcbfd 100644 --- a/backend/tests/setup-tests.ts +++ b/backend/tests/setup-tests.ts @@ -1,30 +1,18 @@ -import { Assignment } from '../src/entities/assignments/assignment.entity.js'; -import { Group } from '../src/entities/assignments/group.entity.js'; -import { Submission } from '../src/entities/assignments/submission.entity.js'; -import { - ClassJoinRequest, - ClassJoinRequestStatus, -} from '../src/entities/classes/class-join-request.entity.js'; -import { Class } from '../src/entities/classes/class.entity.js'; -import { TeacherInvitation } from '../src/entities/classes/teacher-invitation.entity.js'; -import { Attachment } from '../src/entities/content/attachment.entity.js'; -import { Language } from '../src/entities/content/language.js'; -import { - ContentType, - LearningObject, - ReturnValue, -} from '../src/entities/content/learning-object.entity.js'; -import { - LearningPath, - LearningPathNode, - LearningPathTransition, -} from '../src/entities/content/learning-path.entity.js'; -import { Answer } from '../src/entities/questions/answer.entity.js'; -import { Question } from '../src/entities/questions/question.entity.js'; -import { Student } from '../src/entities/users/student.entity.js'; -import { Teacher } from '../src/entities/users/teacher.entity.js'; import { forkEntityManager, initORM } from '../src/orm.js'; import dotenv from 'dotenv'; +import { makeTestStudents } from './test_assets/users/students.testdata.js'; +import { makeTestTeachers } from './test_assets/users/teachers.testdata.js'; +import { makeTestLearningObjects } from './test_assets/content/learning-objects.testdata.js'; +import { makeTestLearningPaths } from './test_assets/content/learning-paths.testdata.js'; +import { makeTestClasses } from './test_assets/classes/classes.testdata.js'; +import { makeTestAssignemnts } from './test_assets/assignments/assignments.testdata.js'; +import { makeTestGroups } from './test_assets/assignments/groups.testdata.js'; +import { makeTestTeacherInvitations } from './test_assets/classes/teacher-invitations.testdata.js'; +import { makeTestClassJoinRequests } from './test_assets/classes/class-join-requests.testdata.js'; +import { makeTestAttachments } from './test_assets/content/attachments.testdata.js'; +import { makeTestQuestions } from './test_assets/questions/questions.testdata.js'; +import { makeTestAnswers } from './test_assets/questions/answers.testdata.js'; +import { makeTestSubmissions } from './test_assets/assignments/submission.testdata.js'; export async function setupTestApp() { dotenv.config({ path: '.env.test' }); @@ -32,616 +20,44 @@ export async function setupTestApp() { const em = forkEntityManager(); - const student01 = em.create(Student, { - username: 'Noordkaap', - firstName: 'Stijn', - lastName: 'Meuris', - }); + const students = makeTestStudents(em); + const teachers = makeTestTeachers(em); + const learningObjects = makeTestLearningObjects(em); + const learningPaths = makeTestLearningPaths(em); + const classes = makeTestClasses(em, students, teachers); + const assignments = makeTestAssignemnts(em, classes); + const groups = makeTestGroups(em, students, assignments); - const student02 = em.create(Student, { - username: 'DireStraits', - firstName: 'Mark', - lastName: 'Knopfler', - }); + assignments[0].groups = groups.slice(0, 3); + assignments[1].groups = groups.slice(3, 4); - const student03 = em.create(Student, { - username: 'Tool', - firstName: 'Maynard', - lastName: 'Keenan', - }); + const teacherInvitations = makeTestTeacherInvitations( + em, + teachers, + classes + ); + const classJoinRequests = makeTestClassJoinRequests(em, students, classes); + const attachments = makeTestAttachments(em, learningObjects); - const student04 = em.create(Student, { - username: 'SmashingPumpkins', - firstName: 'Billy', - lastName: 'Corgan', - }); + learningObjects[1].attachments = attachments; - const student05 = em.create(Student, { - username: 'PinkFloyd', - firstName: 'David', - lastName: 'Gilmoure', - }); - - const student06 = em.create(Student, { - username: 'TheDoors', - firstName: 'Jim', - lastName: 'Morisson', - }); - - const student07 = em.create(Student, { - username: 'Nirvana', - firstName: 'Kurt', - lastName: 'Cobain', - }); - - const teacher01 = em.create(Teacher, { - username: 'FooFighters', - firstName: 'Dave', - lastName: 'Grohl', - }); - - const teacher02 = em.create(Teacher, { - username: 'LimpBizkit', - firstName: 'Fred', - lastName: 'Durst', - }); - - const teacher03 = em.create(Teacher, { - username: 'Staind', - firstName: 'Aaron', - lastName: 'Lewis', - }); - - const teacher04 = em.create(Teacher, { - username: 'ZesdeMetaal', - firstName: 'Wannes', - lastName: 'Cappelle', - }); - - const returnValue: ReturnValue = new ReturnValue(); - returnValue.callbackSchema = ''; - returnValue.callbackUrl = ''; - const learningObject01 = em.create(LearningObject, { - hruid: 'id01', - language: Language.English, - version: '1', - admins: [], - title: 'Undertow', - description: 'debute', - contentType: ContentType.Markdown, - keywords: [], - teacherExclusive: false, - skosConcepts: [], - educationalGoals: [], - copyright: '', - license: '', - estimatedTime: 45, - returnValue: returnValue, - available: true, - contentLocation: '', - attachments: [], - content: Buffer.from( - "there's a shadow just behind me, shrouding every step i take, making every promise empty pointing every finger at me" - ), - }); - - const learningObject02 = em.create(LearningObject, { - hruid: 'id02', - language: Language.English, - version: '1', - admins: [], - title: 'Aenema', - description: 'second album', - contentType: ContentType.Markdown, - keywords: [], - teacherExclusive: false, - skosConcepts: [], - educationalGoals: [], - copyright: '', - license: '', - estimatedTime: 80, - returnValue: returnValue, - available: true, - contentLocation: '', - attachments: [], - content: Buffer.from( - "I've been crawling on my belly clearing out what could've been I've been wallowing in my own confused and insecure delusions" - ), - }); - - const learningObject03 = em.create(LearningObject, { - hruid: 'id03', - language: Language.English, - version: '1', - admins: [], - title: 'love over gold', - description: 'third album', - contentType: ContentType.Markdown, - keywords: [], - teacherExclusive: false, - skosConcepts: [], - educationalGoals: [], - copyright: '', - license: '', - estimatedTime: 55, - returnValue: returnValue, - available: true, - contentLocation: '', - attachments: [], - content: Buffer.from( - 'he wrote me a prescription, he said you are depressed, \ - but I am glad you came to see me to get this off your chest, \ - come back and see me later next patient please \ - send in another victim of industrial disease' - ), - }); - - const learningObject04 = em.create(LearningObject, { - hruid: 'id04', - language: Language.English, - version: '1', - admins: [], - title: 'making movies', - description: 'fifth album', - contentType: ContentType.Markdown, - keywords: [], - teacherExclusive: false, - skosConcepts: [], - educationalGoals: [], - copyright: '', - license: '', - estimatedTime: 55, - returnValue: returnValue, - available: true, - contentLocation: '', - attachments: [], - content: Buffer.from( - 'I put my hand upon the lever \ - Said let it rock and let it roll \ - I had the one-arm bandit fever \ - There was an arrow through my heart and my soul' - ), - }); - - const learningObject05 = em.create(LearningObject, { - hruid: 'id05', - language: Language.English, - version: '1', - admins: [], - title: 'on every street', - description: 'sixth album', - contentType: ContentType.Markdown, - keywords: [], - teacherExclusive: false, - skosConcepts: [], - educationalGoals: [], - copyright: '', - license: '', - estimatedTime: 55, - returnValue: returnValue, - available: true, - contentLocation: '', - attachments: [], - content: Buffer.from( - 'calling Elvis, is anybody home, calling elvis, I am here all alone' - ), - }); - - const learningPathNode01: LearningPathNode = new LearningPathNode(); - const learningPathNode02: LearningPathNode = new LearningPathNode(); - const learningPathNode03: LearningPathNode = new LearningPathNode(); - const learningPathNode04: LearningPathNode = new LearningPathNode(); - const learningPathNode05: LearningPathNode = new LearningPathNode(); - - const transitions01: LearningPathTransition = new LearningPathTransition(); - const transitions02: LearningPathTransition = new LearningPathTransition(); - const transitions03: LearningPathTransition = new LearningPathTransition(); - const transitions04: LearningPathTransition = new LearningPathTransition(); - const transitions05: LearningPathTransition = new LearningPathTransition(); - - transitions01.condition = 'true'; - transitions01.next = learningPathNode02; - - transitions02.condition = 'true'; - transitions02.next = learningPathNode02; - - transitions03.condition = 'true'; - transitions03.next = learningPathNode04; - - transitions04.condition = 'true'; - transitions04.next = learningPathNode05; - - transitions05.condition = 'true'; - transitions05.next = learningPathNode05; - - learningPathNode01.instruction = ''; - learningPathNode01.language = Language.English; - learningPathNode01.learningObjectHruid = 'id01'; - learningPathNode01.startNode = true; - learningPathNode01.transitions = [transitions01]; - learningPathNode01.version = '1'; - - learningPathNode02.instruction = ''; - learningPathNode02.language = Language.English; - learningPathNode02.learningObjectHruid = 'id02'; - learningPathNode02.startNode = false; - learningPathNode02.transitions = [transitions02]; - learningPathNode02.version = '1'; - - learningPathNode03.instruction = ''; - learningPathNode03.language = Language.English; - learningPathNode03.learningObjectHruid = 'id03'; - learningPathNode03.startNode = true; - learningPathNode03.transitions = [transitions03]; - learningPathNode03.version = '1'; - - learningPathNode04.instruction = ''; - learningPathNode04.language = Language.English; - learningPathNode04.learningObjectHruid = 'id04'; - learningPathNode04.startNode = false; - learningPathNode04.transitions = [transitions04]; - learningPathNode04.version = '1'; - - learningPathNode05.instruction = ''; - learningPathNode05.language = Language.English; - learningPathNode05.learningObjectHruid = 'id05'; - learningPathNode05.startNode = false; - learningPathNode05.transitions = [transitions05]; - learningPathNode05.version = '1'; - - const nodes01: Array = [ - // learningPathNode01, - // learningPathNode02, - ]; - const learningPath01 = em.create(LearningPath, { - hruid: 'id01', - language: Language.English, - admins: [], - title: 'repertoire Tool', - description: 'all about Tool', - image: '', - nodes: nodes01, - }); - - const nodes02: Array = [ - // learningPathNode03, - // learningPathNode04, - // learningPathNode05, - ]; - const learningPath02 = em.create(LearningPath, { - hruid: 'id02', - language: Language.English, - admins: [], - title: 'repertoire Dire Straits', - description: 'all about Dire Straits', - image: '', - nodes: nodes02, - }); - - const studentsClass01: Array = [ - student01, - student02, - student03, - student04, - student05, - student06, - ]; - const teacherClass01: Array = [teacher01]; - - const class01 = em.create(Class, { - classId: 'id01', - displayName: 'class01', - teachers: teacherClass01, - students: studentsClass01, - }); - - const studentsClass02: Array = [student01, student02, student04]; - const teacherClass02: Array = [teacher02]; - const class02 = em.create(Class, { - classId: 'id02', - displayName: 'class02', - teachers: teacherClass02, - students: studentsClass02, - }); - - const studentsClass03: Array = [student02, student03, student04]; - const teacherClass03: Array = [teacher03]; - const class03 = em.create(Class, { - classId: 'id03', - displayName: 'class03', - teachers: teacherClass03, - students: studentsClass03, - }); - - const studentsClass04: Array = [student01, student02]; - const teacherClass04: Array = [teacher03]; - const class04 = em.create(Class, { - classId: 'id04', - displayName: 'class04', - teachers: teacherClass04, - students: studentsClass04, - }); - - const assignment01 = em.create(Assignment, { - within: class01, - id: 1, - title: 'dire straits', - description: 'reading', - learningPathHruid: 'id02', - learningPathLanguage: Language.English, - groups: [], - }); - - const assignment02 = em.create(Assignment, { - within: class02, - id: 2, - title: 'tool', - description: 'reading', - learningPathHruid: 'id01', - learningPathLanguage: Language.English, - groups: [], - }); - - const assignment03 = em.create(Assignment, { - within: class01, - id: 3, - title: 'delete', - description: 'will be deleted', - learningPathHruid: 'id02', - learningPathLanguage: Language.English, - groups: [], - }); - - const group01 = em.create(Group, { - assignment: assignment01, - groupNumber: 1, - members: [student01, student02], - }); - - const group02 = em.create(Group, { - assignment: assignment01, - groupNumber: 2, - members: [student03, student04], - }); - - const group03 = em.create(Group, { - assignment: assignment01, - groupNumber: 3, - members: [student05, student06], - }); - - const group04 = em.create(Group, { - assignment: assignment02, - groupNumber: 4, - members: [student04], - }); - - assignment01.groups = [group01, group02, group03]; - assignment02.groups = [group04]; - - const teacherInvitation01 = em.create(TeacherInvitation, { - sender: teacher02, - receiver: teacher01, - class: class02, - }); - - const teacherInvitation02 = em.create(TeacherInvitation, { - sender: teacher02, - receiver: teacher03, - class: class02, - }); - - const teacherInvitation03 = em.create(TeacherInvitation, { - sender: teacher03, - receiver: teacher01, - class: class03, - }); - - const teacherInvitation04 = em.create(TeacherInvitation, { - sender: teacher01, - receiver: teacher02, - class: class01, - }); - - const classJoinRequest01 = em.create(ClassJoinRequest, { - requester: student05, - class: class02, - status: ClassJoinRequestStatus.Open, - }); - - const classJoinRequest02 = em.create(ClassJoinRequest, { - requester: student03, - class: class02, - status: ClassJoinRequestStatus.Open, - }); - - const classJoinRequest03 = em.create(ClassJoinRequest, { - requester: student05, - class: class03, - status: ClassJoinRequestStatus.Open, - }); - - const classJoinRequest04 = em.create(ClassJoinRequest, { - requester: student04, - class: class03, - status: ClassJoinRequestStatus.Open, - }); - - const attachment01 = em.create(Attachment, { - learningObject: learningObject02, - sequenceNumber: 1, - mimeType: '', - content: Buffer.from(''), - }); - - learningObject02.attachments = [attachment01]; - - const question01 = em.create(Question, { - learningObjectLanguage: Language.English, - learningObjectVersion: '1', - learningObjectHruid: 'id05', - sequenceNumber: 1, - author: student01, - timestamp: new Date(), - content: 'question', - }); - - const question02 = em.create(Question, { - learningObjectLanguage: Language.English, - learningObjectVersion: '1', - learningObjectHruid: 'id05', - sequenceNumber: 2, - author: student03, - timestamp: new Date(), - content: 'question', - }); - - const question03 = em.create(Question, { - learningObjectLanguage: Language.English, - learningObjectVersion: '1', - learningObjectHruid: 'id04', - sequenceNumber: 1, - author: student01, - timestamp: new Date(), - content: 'question', - }); - - const question04 = em.create(Question, { - learningObjectLanguage: Language.English, - learningObjectVersion: '1', - learningObjectHruid: 'id01', - sequenceNumber: 1, - author: student02, - timestamp: new Date(), - content: 'question', - }); - - const answer01 = em.create(Answer, { - author: teacher01, - toQuestion: question02, - sequenceNumber: 1, - timestamp: new Date(), - content: 'answer', - }); - - const answer02 = em.create(Answer, { - author: teacher01, - toQuestion: question02, - sequenceNumber: 2, - timestamp: new Date(), - content: 'answer2', - }); - - const answer03 = em.create(Answer, { - author: teacher02, - toQuestion: question04, - sequenceNumber: 1, - timestamp: new Date(), - content: 'answer3', - }); - - const submission01 = em.create(Submission, { - learningObjectHruid: 'id03', - learningObjectLanguage: Language.English, - learningObjectVersion: '1', - submissionNumber: 1, - submitter: student01, - submissionTime: new Date(2025, 2, 20), - onBehalfOf: group01, - content: 'sub1', - }); - - const submission02 = em.create(Submission, { - learningObjectHruid: 'id03', - learningObjectLanguage: Language.English, - learningObjectVersion: '1', - submissionNumber: 2, - submitter: student01, - submissionTime: new Date(2025, 2, 25), - onBehalfOf: group01, - content: '', - }); - - const submission03 = em.create(Submission, { - learningObjectHruid: 'id02', - learningObjectLanguage: Language.English, - learningObjectVersion: '1', - submissionNumber: 1, - submitter: student01, - submissionTime: new Date(2025, 2, 20), - content: '', - }); - - const submission04 = em.create(Submission, { - learningObjectHruid: 'id02', - learningObjectLanguage: Language.English, - learningObjectVersion: '1', - submissionNumber: 2, - submitter: student01, - submissionTime: new Date(2025, 2, 25), - content: '', - }); - - const submission05 = em.create(Submission, { - learningObjectHruid: 'id01', - learningObjectLanguage: Language.English, - learningObjectVersion: '1', - submissionNumber: 1, - submitter: student02, - submissionTime: new Date(2025, 2, 20), - content: '', - }); + const questions = makeTestQuestions(em, students); + const answers = makeTestAnswers(em, teachers, questions); + const submissions = makeTestSubmissions(em, students, groups); await em.persistAndFlush([ - student01, - student02, - student03, - student04, - student05, - student06, - student07, - teacher01, - teacher02, - teacher03, - teacher04, - class01, - class02, - class03, - class04, - learningObject01, - learningObject02, - learningObject03, - learningObject04, - learningObject05, - learningPath01, - learningPath02, - attachment01, - classJoinRequest01, - classJoinRequest02, - classJoinRequest03, - classJoinRequest04, - teacherInvitation01, - teacherInvitation02, - teacherInvitation03, - teacherInvitation04, - assignment01, - assignment02, - assignment03, - group01, - group02, - group03, - group04, - question01, - question02, - question03, - question04, - answer01, - answer02, - answer03, - submission01, - submission02, - submission03, - submission04, - submission05, + ...students, + ...teachers, + ...learningObjects, + ...learningPaths, + ...classes, + ...assignments, + ...groups, + ...teacherInvitations, + ...classJoinRequests, + ...attachments, + ...questions, + ...answers, + ...submissions, ]); } diff --git a/backend/tests/test_assets/assignments/assignments.testdata.ts b/backend/tests/test_assets/assignments/assignments.testdata.ts new file mode 100644 index 00000000..d5dae2d4 --- /dev/null +++ b/backend/tests/test_assets/assignments/assignments.testdata.ts @@ -0,0 +1,41 @@ +import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; +import { Assignment } from '../../../src/entities/assignments/assignment.entity'; +import { Class } from '../../../src/entities/classes/class.entity'; +import { Language } from '../../../src/entities/content/language'; + +export function makeTestAssignemnts( + em: EntityManager>, + classes: Array +): Array { + const assignment01 = em.create(Assignment, { + within: classes[0], + id: 1, + title: 'dire straits', + description: 'reading', + learningPathHruid: 'id02', + learningPathLanguage: Language.English, + groups: [], + }); + + const assignment02 = em.create(Assignment, { + within: classes[1], + id: 2, + title: 'tool', + description: 'reading', + learningPathHruid: 'id01', + learningPathLanguage: Language.English, + groups: [], + }); + + const assignment03 = em.create(Assignment, { + within: classes[0], + id: 3, + title: 'delete', + description: 'will be deleted', + learningPathHruid: 'id02', + learningPathLanguage: Language.English, + groups: [], + }); + + return [assignment01, assignment02, assignment03]; +} diff --git a/backend/tests/test_assets/assignments/groups.testdata.ts b/backend/tests/test_assets/assignments/groups.testdata.ts new file mode 100644 index 00000000..0e9ef201 --- /dev/null +++ b/backend/tests/test_assets/assignments/groups.testdata.ts @@ -0,0 +1,36 @@ +import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; +import { Group } from '../../../src/entities/assignments/group.entity'; +import { Assignment } from '../../../src/entities/assignments/assignment.entity'; +import { Student } from '../../../src/entities/users/student.entity'; + +export function makeTestGroups( + em: EntityManager>, + students: Array, + assignments: Array +): Array { + const group01 = em.create(Group, { + assignment: assignments[0], + groupNumber: 1, + members: students.slice(0, 2), + }); + + const group02 = em.create(Group, { + assignment: assignments[0], + groupNumber: 2, + members: students.slice(2, 4), + }); + + const group03 = em.create(Group, { + assignment: assignments[0], + groupNumber: 3, + members: students.slice(4, 6), + }); + + const group04 = em.create(Group, { + assignment: assignments[1], + groupNumber: 4, + members: students.slice(3, 4), + }); + + return [group01, group02, group03, group04]; +} diff --git a/backend/tests/test_assets/assignments/submission.testdata.ts b/backend/tests/test_assets/assignments/submission.testdata.ts new file mode 100644 index 00000000..1e943926 --- /dev/null +++ b/backend/tests/test_assets/assignments/submission.testdata.ts @@ -0,0 +1,71 @@ +import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; +import { Submission } from '../../../src/entities/assignments/submission.entity'; +import { Language } from '../../../src/entities/content/language'; +import { Student } from '../../../src/entities/users/student.entity'; +import { Group } from '../../../src/entities/assignments/group.entity'; + +export function makeTestSubmissions( + em: EntityManager>, + students: Array, + groups: Array +): Array { + const submission01 = em.create(Submission, { + learningObjectHruid: 'id03', + learningObjectLanguage: Language.English, + learningObjectVersion: '1', + submissionNumber: 1, + submitter: students[0], + submissionTime: new Date(2025, 2, 20), + onBehalfOf: groups[0], + content: 'sub1', + }); + + const submission02 = em.create(Submission, { + learningObjectHruid: 'id03', + learningObjectLanguage: Language.English, + learningObjectVersion: '1', + submissionNumber: 2, + submitter: students[0], + submissionTime: new Date(2025, 2, 25), + onBehalfOf: groups[0], + content: '', + }); + + const submission03 = em.create(Submission, { + learningObjectHruid: 'id02', + learningObjectLanguage: Language.English, + learningObjectVersion: '1', + submissionNumber: 1, + submitter: students[0], + submissionTime: new Date(2025, 2, 20), + content: '', + }); + + const submission04 = em.create(Submission, { + learningObjectHruid: 'id02', + learningObjectLanguage: Language.English, + learningObjectVersion: '1', + submissionNumber: 2, + submitter: students[0], + submissionTime: new Date(2025, 2, 25), + content: '', + }); + + const submission05 = em.create(Submission, { + learningObjectHruid: 'id01', + learningObjectLanguage: Language.English, + learningObjectVersion: '1', + submissionNumber: 1, + submitter: students[1], + submissionTime: new Date(2025, 2, 20), + content: '', + }); + + return [ + submission01, + submission02, + submission03, + submission04, + submission05, + ]; +} diff --git a/backend/tests/test_assets/classes/class-join-requests.testdata.ts b/backend/tests/test_assets/classes/class-join-requests.testdata.ts new file mode 100644 index 00000000..e770ed6c --- /dev/null +++ b/backend/tests/test_assets/classes/class-join-requests.testdata.ts @@ -0,0 +1,44 @@ +import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; +import { + ClassJoinRequest, + ClassJoinRequestStatus, +} from '../../../src/entities/classes/class-join-request.entity'; +import { Student } from '../../../src/entities/users/student.entity'; +import { Class } from '../../../src/entities/classes/class.entity'; + +export function makeTestClassJoinRequests( + em: EntityManager>, + students: Array, + classes: Array +): Array { + const classJoinRequest01 = em.create(ClassJoinRequest, { + requester: students[4], + class: classes[1], + status: ClassJoinRequestStatus.Open, + }); + + const classJoinRequest02 = em.create(ClassJoinRequest, { + requester: students[2], + class: classes[1], + status: ClassJoinRequestStatus.Open, + }); + + const classJoinRequest03 = em.create(ClassJoinRequest, { + requester: students[4], + class: classes[2], + status: ClassJoinRequestStatus.Open, + }); + + const classJoinRequest04 = em.create(ClassJoinRequest, { + requester: students[3], + class: classes[2], + status: ClassJoinRequestStatus.Open, + }); + + return [ + classJoinRequest01, + classJoinRequest02, + classJoinRequest03, + classJoinRequest04, + ]; +} diff --git a/backend/tests/test_assets/classes/classes.testdata.ts b/backend/tests/test_assets/classes/classes.testdata.ts new file mode 100644 index 00000000..b3c93747 --- /dev/null +++ b/backend/tests/test_assets/classes/classes.testdata.ts @@ -0,0 +1,54 @@ +import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; +import { Class } from '../../../src/entities/classes/class.entity'; +import { Student } from '../../../src/entities/users/student.entity'; +import { Teacher } from '../../../src/entities/users/teacher.entity'; + +export function makeTestClasses( + em: EntityManager>, + students: Array, + teachers: Array +): Array { + const studentsClass01 = students.slice(0, 7); + const teacherClass01: Array = teachers.slice(0, 1); + + const class01 = em.create(Class, { + classId: 'id01', + displayName: 'class01', + teachers: teacherClass01, + students: studentsClass01, + }); + + const studentsClass02: Array = students + .slice(0, 2) + .concat(students.slice(3, 4)); + const teacherClass02: Array = teachers.slice(1, 2); + + const class02 = em.create(Class, { + classId: 'id02', + displayName: 'class02', + teachers: teacherClass02, + students: studentsClass02, + }); + + const studentsClass03: Array = students.slice(1, 4); + const teacherClass03: Array = teachers.slice(2, 3); + + const class03 = em.create(Class, { + classId: 'id03', + displayName: 'class03', + teachers: teacherClass03, + students: studentsClass03, + }); + + const studentsClass04: Array = students.slice(0, 2); + const teacherClass04: Array = teachers.slice(2, 3); + + const class04 = em.create(Class, { + classId: 'id04', + displayName: 'class04', + teachers: teacherClass04, + students: studentsClass04, + }); + + return [class01, class02, class03, class04]; +} diff --git a/backend/tests/test_assets/classes/teacher-invitations.testdata.ts b/backend/tests/test_assets/classes/teacher-invitations.testdata.ts new file mode 100644 index 00000000..ad5297ff --- /dev/null +++ b/backend/tests/test_assets/classes/teacher-invitations.testdata.ts @@ -0,0 +1,41 @@ +import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; +import { TeacherInvitation } from '../../../src/entities/classes/teacher-invitation.entity'; +import { Teacher } from '../../../src/entities/users/teacher.entity'; +import { Class } from '../../../src/entities/classes/class.entity'; + +export function makeTestTeacherInvitations( + em: EntityManager>, + teachers: Array, + classes: Array +): Array { + const teacherInvitation01 = em.create(TeacherInvitation, { + sender: teachers[1], + receiver: teachers[0], + class: classes[1], + }); + + const teacherInvitation02 = em.create(TeacherInvitation, { + sender: teachers[1], + receiver: teachers[2], + class: classes[1], + }); + + const teacherInvitation03 = em.create(TeacherInvitation, { + sender: teachers[2], + receiver: teachers[0], + class: classes[2], + }); + + const teacherInvitation04 = em.create(TeacherInvitation, { + sender: teachers[0], + receiver: teachers[1], + class: classes[0], + }); + + return [ + teacherInvitation01, + teacherInvitation02, + teacherInvitation03, + teacherInvitation04, + ]; +} diff --git a/backend/tests/test_assets/content/attachments.testdata.ts b/backend/tests/test_assets/content/attachments.testdata.ts new file mode 100644 index 00000000..a1d362e3 --- /dev/null +++ b/backend/tests/test_assets/content/attachments.testdata.ts @@ -0,0 +1,17 @@ +import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; +import { Attachment } from '../../../src/entities/content/attachment.entity'; +import { LearningObject } from '../../../src/entities/content/learning-object.entity'; + +export function makeTestAttachments( + em: EntityManager>, + learningObjects: Array +): Array { + const attachment01 = em.create(Attachment, { + learningObject: learningObjects[1], + sequenceNumber: 1, + mimeType: '', + content: Buffer.from(''), + }); + + return [attachment01]; +} diff --git a/backend/tests/test_assets/content/learning-objects.testdata.ts b/backend/tests/test_assets/content/learning-objects.testdata.ts new file mode 100644 index 00000000..479f8102 --- /dev/null +++ b/backend/tests/test_assets/content/learning-objects.testdata.ts @@ -0,0 +1,149 @@ +import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; +import { + ContentType, + LearningObject, + ReturnValue, +} from '../../../src/entities/content/learning-object.entity'; +import { Language } from '../../../src/entities/content/language'; + +export function makeTestLearningObjects( + em: EntityManager> +): Array { + const returnValue: ReturnValue = new ReturnValue(); + returnValue.callbackSchema = ''; + returnValue.callbackUrl = ''; + + const learningObject01 = em.create(LearningObject, { + hruid: 'id01', + language: Language.English, + version: '1', + admins: [], + title: 'Undertow', + description: 'debute', + contentType: ContentType.Markdown, + keywords: [], + teacherExclusive: false, + skosConcepts: [], + educationalGoals: [], + copyright: '', + license: '', + estimatedTime: 45, + returnValue: returnValue, + available: true, + contentLocation: '', + attachments: [], + content: Buffer.from( + "there's a shadow just behind me, shrouding every step i take, making every promise empty pointing every finger at me" + ), + }); + + const learningObject02 = em.create(LearningObject, { + hruid: 'id02', + language: Language.English, + version: '1', + admins: [], + title: 'Aenema', + description: 'second album', + contentType: ContentType.Markdown, + keywords: [], + teacherExclusive: false, + skosConcepts: [], + educationalGoals: [], + copyright: '', + license: '', + estimatedTime: 80, + returnValue: returnValue, + available: true, + contentLocation: '', + attachments: [], + content: Buffer.from( + "I've been crawling on my belly clearing out what could've been I've been wallowing in my own confused and insecure delusions" + ), + }); + + const learningObject03 = em.create(LearningObject, { + hruid: 'id03', + language: Language.English, + version: '1', + admins: [], + title: 'love over gold', + description: 'third album', + contentType: ContentType.Markdown, + keywords: [], + teacherExclusive: false, + skosConcepts: [], + educationalGoals: [], + copyright: '', + license: '', + estimatedTime: 55, + returnValue: returnValue, + available: true, + contentLocation: '', + attachments: [], + content: Buffer.from( + 'he wrote me a prescription, he said you are depressed, \ + but I am glad you came to see me to get this off your chest, \ + come back and see me later next patient please \ + send in another victim of industrial disease' + ), + }); + + const learningObject04 = em.create(LearningObject, { + hruid: 'id04', + language: Language.English, + version: '1', + admins: [], + title: 'making movies', + description: 'fifth album', + contentType: ContentType.Markdown, + keywords: [], + teacherExclusive: false, + skosConcepts: [], + educationalGoals: [], + copyright: '', + license: '', + estimatedTime: 55, + returnValue: returnValue, + available: true, + contentLocation: '', + attachments: [], + content: Buffer.from( + 'I put my hand upon the lever \ + Said let it rock and let it roll \ + I had the one-arm bandit fever \ + There was an arrow through my heart and my soul' + ), + }); + + const learningObject05 = em.create(LearningObject, { + hruid: 'id05', + language: Language.English, + version: '1', + admins: [], + title: 'on every street', + description: 'sixth album', + contentType: ContentType.Markdown, + keywords: [], + teacherExclusive: false, + skosConcepts: [], + educationalGoals: [], + copyright: '', + license: '', + estimatedTime: 55, + returnValue: returnValue, + available: true, + contentLocation: '', + attachments: [], + content: Buffer.from( + 'calling Elvis, is anybody home, calling elvis, I am here all alone' + ), + }); + + return [ + learningObject01, + learningObject02, + learningObject03, + learningObject04, + learningObject05, + ]; +} diff --git a/backend/tests/test_assets/content/learning-paths.testdata.ts b/backend/tests/test_assets/content/learning-paths.testdata.ts new file mode 100644 index 00000000..c540860a --- /dev/null +++ b/backend/tests/test_assets/content/learning-paths.testdata.ts @@ -0,0 +1,104 @@ +import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; +import { + LearningPath, + LearningPathNode, + LearningPathTransition, +} from '../../../src/entities/content/learning-path.entity'; +import { Language } from '../../../src/entities/content/language'; + +export function makeTestLearningPaths( + em: EntityManager> +): Array { + const learningPathNode01: LearningPathNode = new LearningPathNode(); + const learningPathNode02: LearningPathNode = new LearningPathNode(); + const learningPathNode03: LearningPathNode = new LearningPathNode(); + const learningPathNode04: LearningPathNode = new LearningPathNode(); + const learningPathNode05: LearningPathNode = new LearningPathNode(); + + const transitions01: LearningPathTransition = new LearningPathTransition(); + const transitions02: LearningPathTransition = new LearningPathTransition(); + const transitions03: LearningPathTransition = new LearningPathTransition(); + const transitions04: LearningPathTransition = new LearningPathTransition(); + const transitions05: LearningPathTransition = new LearningPathTransition(); + + transitions01.condition = 'true'; + transitions01.next = learningPathNode02; + + transitions02.condition = 'true'; + transitions02.next = learningPathNode02; + + transitions03.condition = 'true'; + transitions03.next = learningPathNode04; + + transitions04.condition = 'true'; + transitions04.next = learningPathNode05; + + transitions05.condition = 'true'; + transitions05.next = learningPathNode05; + + learningPathNode01.instruction = ''; + learningPathNode01.language = Language.English; + learningPathNode01.learningObjectHruid = 'id01'; + learningPathNode01.startNode = true; + learningPathNode01.transitions = [transitions01]; + learningPathNode01.version = '1'; + + learningPathNode02.instruction = ''; + learningPathNode02.language = Language.English; + learningPathNode02.learningObjectHruid = 'id02'; + learningPathNode02.startNode = false; + learningPathNode02.transitions = [transitions02]; + learningPathNode02.version = '1'; + + learningPathNode03.instruction = ''; + learningPathNode03.language = Language.English; + learningPathNode03.learningObjectHruid = 'id03'; + learningPathNode03.startNode = true; + learningPathNode03.transitions = [transitions03]; + learningPathNode03.version = '1'; + + learningPathNode04.instruction = ''; + learningPathNode04.language = Language.English; + learningPathNode04.learningObjectHruid = 'id04'; + learningPathNode04.startNode = false; + learningPathNode04.transitions = [transitions04]; + learningPathNode04.version = '1'; + + learningPathNode05.instruction = ''; + learningPathNode05.language = Language.English; + learningPathNode05.learningObjectHruid = 'id05'; + learningPathNode05.startNode = false; + learningPathNode05.transitions = [transitions05]; + learningPathNode05.version = '1'; + + const nodes01: Array = [ + // learningPathNode01, + // learningPathNode02, + ]; + const learningPath01 = em.create(LearningPath, { + hruid: 'id01', + language: Language.English, + admins: [], + title: 'repertoire Tool', + description: 'all about Tool', + image: '', + nodes: nodes01, + }); + + const nodes02: Array = [ + // learningPathNode03, + // learningPathNode04, + // learningPathNode05, + ]; + const learningPath02 = em.create(LearningPath, { + hruid: 'id02', + language: Language.English, + admins: [], + title: 'repertoire Dire Straits', + description: 'all about Dire Straits', + image: '', + nodes: nodes02, + }); + + return [learningPath01, learningPath02]; +} diff --git a/backend/tests/test_assets/questions/answers.testdata.ts b/backend/tests/test_assets/questions/answers.testdata.ts new file mode 100644 index 00000000..90039922 --- /dev/null +++ b/backend/tests/test_assets/questions/answers.testdata.ts @@ -0,0 +1,36 @@ +import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; +import { Answer } from '../../../src/entities/questions/answer.entity'; +import { Teacher } from '../../../src/entities/users/teacher.entity'; +import { Question } from '../../../src/entities/questions/question.entity'; + +export function makeTestAnswers( + em: EntityManager>, + teachers: Array, + questions: Array +): Array { + const answer01 = em.create(Answer, { + author: teachers[0], + toQuestion: questions[1], + sequenceNumber: 1, + timestamp: new Date(), + content: 'answer', + }); + + const answer02 = em.create(Answer, { + author: teachers[0], + toQuestion: questions[1], + sequenceNumber: 2, + timestamp: new Date(), + content: 'answer2', + }); + + const answer03 = em.create(Answer, { + author: teachers[1], + toQuestion: questions[3], + sequenceNumber: 1, + timestamp: new Date(), + content: 'answer3', + }); + + return [answer01, answer02, answer03]; +} diff --git a/backend/tests/test_assets/questions/questions.testdata.ts b/backend/tests/test_assets/questions/questions.testdata.ts new file mode 100644 index 00000000..781cb9c3 --- /dev/null +++ b/backend/tests/test_assets/questions/questions.testdata.ts @@ -0,0 +1,51 @@ +import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; +import { Question } from '../../../src/entities/questions/question.entity'; +import { Language } from '../../../src/entities/content/language'; +import { Student } from '../../../src/entities/users/student.entity'; + +export function makeTestQuestions( + em: EntityManager>, + students: Array +): Array { + const question01 = em.create(Question, { + learningObjectLanguage: Language.English, + learningObjectVersion: '1', + learningObjectHruid: 'id05', + sequenceNumber: 1, + author: students[0], + timestamp: new Date(), + content: 'question', + }); + + const question02 = em.create(Question, { + learningObjectLanguage: Language.English, + learningObjectVersion: '1', + learningObjectHruid: 'id05', + sequenceNumber: 2, + author: students[2], + timestamp: new Date(), + content: 'question', + }); + + const question03 = em.create(Question, { + learningObjectLanguage: Language.English, + learningObjectVersion: '1', + learningObjectHruid: 'id04', + sequenceNumber: 1, + author: students[0], + timestamp: new Date(), + content: 'question', + }); + + const question04 = em.create(Question, { + learningObjectLanguage: Language.English, + learningObjectVersion: '1', + learningObjectHruid: 'id01', + sequenceNumber: 1, + author: students[1], + timestamp: new Date(), + content: 'question', + }); + + return [question01, question02, question03, question04]; +} diff --git a/backend/tests/test_assets/users/students.testdata.ts b/backend/tests/test_assets/users/students.testdata.ts new file mode 100644 index 00000000..5e024085 --- /dev/null +++ b/backend/tests/test_assets/users/students.testdata.ts @@ -0,0 +1,59 @@ +import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; +import { Student } from '../../../src/entities/users/student.entity'; + +export function makeTestStudents( + em: EntityManager> +): Array { + const student01 = em.create(Student, { + username: 'Noordkaap', + firstName: 'Stijn', + lastName: 'Meuris', + }); + + const student02 = em.create(Student, { + username: 'DireStraits', + firstName: 'Mark', + lastName: 'Knopfler', + }); + + const student03 = em.create(Student, { + username: 'Tool', + firstName: 'Maynard', + lastName: 'Keenan', + }); + + const student04 = em.create(Student, { + username: 'SmashingPumpkins', + firstName: 'Billy', + lastName: 'Corgan', + }); + + const student05 = em.create(Student, { + username: 'PinkFloyd', + firstName: 'David', + lastName: 'Gilmoure', + }); + + const student06 = em.create(Student, { + username: 'TheDoors', + firstName: 'Jim', + lastName: 'Morisson', + }); + + // do not use for any tests, gets deleted in a unit test + const student07 = em.create(Student, { + username: 'Nirvana', + firstName: 'Kurt', + lastName: 'Cobain', + }); + + return [ + student01, + student02, + student03, + student04, + student05, + student06, + student07, + ]; +} diff --git a/backend/tests/test_assets/users/teachers.testdata.ts b/backend/tests/test_assets/users/teachers.testdata.ts new file mode 100644 index 00000000..b53a5c5e --- /dev/null +++ b/backend/tests/test_assets/users/teachers.testdata.ts @@ -0,0 +1,33 @@ +import { Teacher } from '../../../src/entities/users/teacher.entity'; +import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; + +export function makeTestTeachers( + em: EntityManager> +): Array { + const teacher01 = em.create(Teacher, { + username: 'FooFighters', + firstName: 'Dave', + lastName: 'Grohl', + }); + + const teacher02 = em.create(Teacher, { + username: 'LimpBizkit', + firstName: 'Fred', + lastName: 'Durst', + }); + + const teacher03 = em.create(Teacher, { + username: 'Staind', + firstName: 'Aaron', + lastName: 'Lewis', + }); + + // should not be used, gets deleted in a unit test + const teacher04 = em.create(Teacher, { + username: 'ZesdeMetaal', + firstName: 'Wannes', + lastName: 'Cappelle', + }); + + return [teacher01, teacher02, teacher03, teacher04]; +} From 7018a8822d286833e79850facc7780644c83e5d2 Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Mon, 10 Mar 2025 21:14:40 +0100 Subject: [PATCH 127/180] test(backend): Testen voor DatabaseLearningPathProvider.fetchLearningPaths afgewerkt Hierbij optredende problemen opgelost. --- .../content/learning-object-repository.ts | 33 +++++++---- .../data/content/learning-path-repository.ts | 9 ++- backend/src/data/repositories.ts | 4 ++ .../content/learning-path-node.entity.ts | 3 +- .../learning-path-transition.entity.ts | 2 +- backend/src/interfaces/learning-content.ts | 4 +- .../database-learning-path-provider.test.ts | 31 +++++++++- .../learning-paths/learning-path-utils.ts | 9 ++- .../learning-paths/pn-werking-example.ts | 17 +++--- backend/tests/test-utils/expectations.ts | 59 ++++++++++++++++++- 10 files changed, 139 insertions(+), 32 deletions(-) diff --git a/backend/src/data/content/learning-object-repository.ts b/backend/src/data/content/learning-object-repository.ts index d69ae075..8fdf18fe 100644 --- a/backend/src/data/content/learning-object-repository.ts +++ b/backend/src/data/content/learning-object-repository.ts @@ -7,21 +7,30 @@ export class LearningObjectRepository extends DwengoEntityRepository { - return this.findOne({ - hruid: identifier.hruid, - language: identifier.language, - version: identifier.version, - }); + return this.findOne( + { + hruid: identifier.hruid, + language: identifier.language, + version: identifier.version, + }, + { + populate: ["keywords"] + } + ); } public findLatestByHruidAndLanguage(hruid: string, language: Language) { - return this.findOne({ - hruid: hruid, - language: language - }, { - orderBy: { - version: "DESC" + return this.findOne( + { + hruid: hruid, + language: language + }, + { + populate: ["keywords"], + orderBy: { + version: "DESC" + } } - }); + ); } } diff --git a/backend/src/data/content/learning-path-repository.ts b/backend/src/data/content/learning-path-repository.ts index 66ef54d0..347bc023 100644 --- a/backend/src/data/content/learning-path-repository.ts +++ b/backend/src/data/content/learning-path-repository.ts @@ -7,7 +7,10 @@ export class LearningPathRepository extends DwengoEntityRepository hruid: string, language: Language ): Promise { - return this.findOne({ hruid: hruid, language: language }); + return this.findOne( + { hruid: hruid, language: language }, + { populate: ["nodes", "nodes.transitions"] } + ); } /** @@ -25,8 +28,8 @@ export class LearningPathRepository extends DwengoEntityRepository { title: { $like: `%${query}%`} }, { description: { $like: `%${query}%`} } ] - } + }, + populate: ["nodes", "nodes.transitions"] }); } - // This repository is read-only for now since creating own learning object is an extension feature. } diff --git a/backend/src/data/repositories.ts b/backend/src/data/repositories.ts index 800d5485..6218bafc 100644 --- a/backend/src/data/repositories.ts +++ b/backend/src/data/repositories.ts @@ -33,6 +33,8 @@ import { LearningPath } from '../entities/content/learning-path.entity.js'; import { LearningPathRepository } from './content/learning-path-repository.js'; import { AttachmentRepository } from './content/attachment-repository.js'; import { Attachment } from '../entities/content/attachment.entity.js'; +import {LearningPathNode} from "../entities/content/learning-path-node.entity"; +import {LearningPathTransition} from "../entities/content/learning-path-transition.entity"; let entityManager: EntityManager | undefined; @@ -113,6 +115,8 @@ export const getLearningPathRepository = repositoryGetter< LearningPath, LearningPathRepository >(LearningPath); +export const getLearningPathNodeRepository = repositoryGetter(LearningPathNode); +export const getLearningPathTransitionRepository = repositoryGetter(LearningPathTransition); export const getAttachmentRepository = repositoryGetter< Attachment, AttachmentRepository diff --git a/backend/src/entities/content/learning-path-node.entity.ts b/backend/src/entities/content/learning-path-node.entity.ts index e15b033a..e2fbdbb3 100644 --- a/backend/src/entities/content/learning-path-node.entity.ts +++ b/backend/src/entities/content/learning-path-node.entity.ts @@ -5,10 +5,11 @@ import {LearningPathTransition} from "./learning-path-transition.entity"; @Entity() export class LearningPathNode { + @ManyToOne({ entity: () => LearningPath, primary: true }) learningPath!: LearningPath; - @PrimaryKey({ type: "numeric", autoincrement: true }) + @PrimaryKey({ type: "integer", autoincrement: true }) nodeNumber!: number; @Property({ type: 'string' }) diff --git a/backend/src/entities/content/learning-path-transition.entity.ts b/backend/src/entities/content/learning-path-transition.entity.ts index 6122b758..dfbe110e 100644 --- a/backend/src/entities/content/learning-path-transition.entity.ts +++ b/backend/src/entities/content/learning-path-transition.entity.ts @@ -3,7 +3,7 @@ import {LearningPathNode} from "./learning-path-node.entity"; @Entity() export class LearningPathTransition { - @ManyToOne({entity: () => LearningPathNode }) + @ManyToOne({entity: () => LearningPathNode, primary: true }) node!: LearningPathNode; @PrimaryKey({ type: 'numeric' }) diff --git a/backend/src/interfaces/learning-content.ts b/backend/src/interfaces/learning-content.ts index 861996f5..89a1340c 100644 --- a/backend/src/interfaces/learning-content.ts +++ b/backend/src/interfaces/learning-content.ts @@ -21,7 +21,7 @@ export interface LearningObjectNode { _id: string; learningobject_hruid: string; version: number; - language: string; + language: Language; start_node?: boolean; transitions: Transition[]; created_at: string; @@ -88,7 +88,7 @@ export interface FilteredLearningObject { version: number; title: string; htmlUrl: string; - language: string; + language: Language; difficulty: number; estimatedTime: number; available: boolean; diff --git a/backend/tests/services/learning-objects/database-learning-path-provider.test.ts b/backend/tests/services/learning-objects/database-learning-path-provider.test.ts index dab40a69..321fe213 100644 --- a/backend/tests/services/learning-objects/database-learning-path-provider.test.ts +++ b/backend/tests/services/learning-objects/database-learning-path-provider.test.ts @@ -6,6 +6,10 @@ import {getLearningObjectRepository, getLearningPathRepository} from "../../../s import learningObjectExample from "../../test-assets/learning-objects/pn_werkingnotebooks/pn-werkingnotebooks-example"; import learningPathExample from "../../test-assets/learning-paths/pn-werking-example" import databaseLearningPathProvider from "../../../src/services/learning-paths/database-learning-path-provider"; +import {expectToBeCorrectLearningPath} from "../../test-utils/expectations"; +import {LearningObjectRepository} from "../../../src/data/content/learning-object-repository"; +import learningObjectService from "../../../src/services/learning-objects/learning-object-service"; +import {Language} from "../../../src/entities/content/language"; async function initExampleData(): Promise<{ learningObject: LearningObject, learningPath: LearningPath }> { const learningObjectRepo = getLearningObjectRepository(); @@ -18,15 +22,17 @@ async function initExampleData(): Promise<{ learningObject: LearningObject, lear } describe("DatabaseLearningPathProvider", () => { + let learningObjectRepo: LearningObjectRepository; let example: {learningObject: LearningObject, learningPath: LearningPath}; beforeAll(async () => { await setupTestApp(); example = await initExampleData(); + learningObjectRepo = getLearningObjectRepository(); }); describe("fetchLearningPaths", () => { - it("returns the learning path correctly", () => { + it("returns the learning path correctly", async () => { const result = await databaseLearningPathProvider.fetchLearningPaths( [example.learningPath.hruid], example.learningPath.language, @@ -34,7 +40,26 @@ describe("DatabaseLearningPathProvider", () => { ); expect(result.success).toBe(true); expect(result.data?.length).toBe(1); - expect(result.data) - }) + + const learningObjectsOnPath = (await Promise.all( + example.learningPath.nodes.map(node => + learningObjectService.getLearningObjectById({ + hruid: node.learningObjectHruid, + version: node.version, + language: node.language + })) + )).filter(it => it !== null); + + expectToBeCorrectLearningPath(result.data![0], example.learningPath, learningObjectsOnPath) + }); + it("returns a non-successful response if a non-existing learning path is queried", async () => { + const result = await databaseLearningPathProvider.fetchLearningPaths( + [example.learningPath.hruid], + Language.Abkhazian, // wrong language + "the source" + ); + + expect(result.success).toBe(false); + }); }); }); diff --git a/backend/tests/test-assets/learning-paths/learning-path-utils.ts b/backend/tests/test-assets/learning-paths/learning-path-utils.ts index 31374869..68c49412 100644 --- a/backend/tests/test-assets/learning-paths/learning-path-utils.ts +++ b/backend/tests/test-assets/learning-paths/learning-path-utils.ts @@ -1,21 +1,28 @@ import {Language} from "../../../src/entities/content/language"; import {LearningPathTransition} from "../../../src/entities/content/learning-path-transition.entity"; import {LearningPathNode} from "../../../src/entities/content/learning-path-node.entity"; +import {LearningPath} from "../../../src/entities/content/learning-path.entity"; -export function createLearningPathTransition(condition: string | null, to: LearningPathNode) { +export function createLearningPathTransition(node: LearningPathNode, transitionNumber: number, condition: string | null, to: LearningPathNode) { let trans = new LearningPathTransition(); + trans.node = node; + trans.transitionNumber = transitionNumber; trans.condition = condition || "true"; trans.next = to; return trans; } export function createLearningPathNode( + learningPath: LearningPath, + nodeNumber: number, learningObjectHruid: string, version: number, language: Language, startNode: boolean ) { let node = new LearningPathNode(); + node.learningPath = learningPath; + node.nodeNumber = nodeNumber; node.learningObjectHruid = learningObjectHruid; node.version = version; node.language = language; diff --git a/backend/tests/test-assets/learning-paths/pn-werking-example.ts b/backend/tests/test-assets/learning-paths/pn-werking-example.ts index dbf86052..a96de552 100644 --- a/backend/tests/test-assets/learning-paths/pn-werking-example.ts +++ b/backend/tests/test-assets/learning-paths/pn-werking-example.ts @@ -1,16 +1,17 @@ -import {LearningPath, LearningPathNode} from "../../../src/entities/content/learning-path.entity"; +import {LearningPath} from "../../../src/entities/content/learning-path.entity"; import {Language} from "../../../src/entities/content/language"; import {EnvVars, getEnvVar} from "../../../src/util/envvars"; import {createLearningPathNode, createLearningPathTransition} from "./learning-path-utils"; +import {LearningPathNode} from "../../../src/entities/content/learning-path-node.entity"; -function createNodes(): LearningPathNode[] { +function createNodes(learningPath: LearningPath): LearningPathNode[] { let nodes = [ - createLearningPathNode("u_pn_werkingnotebooks", 3, Language.Dutch, true), - createLearningPathNode("pn_werkingnotebooks2", 3, Language.Dutch, false), - createLearningPathNode("pn_werkingnotebooks3", 3, Language.Dutch, false), + createLearningPathNode(learningPath, 0, "u_pn_werkingnotebooks", 3, Language.Dutch, true), + createLearningPathNode(learningPath, 1, "pn_werkingnotebooks2", 3, Language.Dutch, false), + createLearningPathNode(learningPath, 2, "pn_werkingnotebooks3", 3, Language.Dutch, false), ]; - nodes[0].transitions.push(createLearningPathTransition("true", nodes[1])); - nodes[1].transitions.push(createLearningPathTransition("true", nodes[2])); + nodes[0].transitions.push(createLearningPathTransition(nodes[0], 0, "true", nodes[1])); + nodes[1].transitions.push(createLearningPathTransition(nodes[1], 0, "true", nodes[2])); return nodes; } @@ -21,7 +22,7 @@ const example: LearningPathExample = { path.hruid = `${getEnvVar(EnvVars.UserContentPrefix)}pn_werking`; path.title = "Werken met notebooks"; path.description = "Een korte inleiding tot Python notebooks. Hoe ga je gemakkelijk en efficiënt met de notebooks aan de slag?"; - path.nodes = createNodes(); + path.nodes = createNodes(path); return path; } } diff --git a/backend/tests/test-utils/expectations.ts b/backend/tests/test-utils/expectations.ts index 285c001a..19c2408d 100644 --- a/backend/tests/test-utils/expectations.ts +++ b/backend/tests/test-utils/expectations.ts @@ -99,9 +99,66 @@ export function expectToBeCorrectFilteredLearningObject(filtered: FilteredLearni * * @param learningPath The learning path returned by the retriever, service or endpoint * @param expectedEntity The expected entity + * @param learningObjectsOnPath The learning objects on LearningPath. Necessary since some information in + * the learning path returned from the API endpoint */ -export function expectToBeCorrectLearningPath(learningPath: LearningPath, expectedEntity: LearningPathEntity) { +export function expectToBeCorrectLearningPath( + learningPath: LearningPath, + expectedEntity: LearningPathEntity, + learningObjectsOnPath: FilteredLearningObject[] +) { expect(learningPath.hruid).toEqual(expectedEntity.hruid); expect(learningPath.language).toEqual(expectedEntity.language); expect(learningPath.description).toEqual(expectedEntity.description); + expect(learningPath.title).toEqual(expectedEntity.title); + + const keywords = new Set(learningObjectsOnPath.flatMap(it => it.keywords || [])); + expect(new Set(learningPath.keywords.split(' '))).toEqual(keywords) + + const targetAges = new Set(learningObjectsOnPath.flatMap(it => it.targetAges || [])); + expect(new Set(learningPath.target_ages)).toEqual(targetAges); + expect(learningPath.min_age).toEqual(Math.min(...targetAges)); + expect(learningPath.max_age).toEqual(Math.max(...targetAges)); + + expect(learningPath.num_nodes).toEqual(expectedEntity.nodes.length); + expect(learningPath.image || null).toEqual(expectedEntity.image); + + let expectedLearningPathNodes = new Map( + expectedEntity.nodes.map(node => [ + {learningObjectHruid: node.learningObjectHruid, language: node.language, version: node.version}, + {startNode: node.startNode, transitions: node.transitions} + ]) + ); + + for (let node of learningPath.nodes) { + const nodeKey = { + learningObjectHruid: node.learningobject_hruid, + language: node.language, + version: node.version + }; + expect(expectedLearningPathNodes.keys()).toContainEqual(nodeKey); + let expectedNode = [...expectedLearningPathNodes.entries()] + .filter(([key, _]) => + key.learningObjectHruid === nodeKey.learningObjectHruid + && key.language === node.language + && key.version === node.version + )[0][1] + expect(node.start_node).toEqual(expectedNode?.startNode); + + expect( + new Set(node.transitions.map(it => it.next.hruid)) + ).toEqual( + new Set(expectedNode.transitions.map(it => it.next.learningObjectHruid)) + ); + expect( + new Set(node.transitions.map(it => it.next.language)) + ).toEqual( + new Set(expectedNode.transitions.map(it => it.next.language)) + ); + expect( + new Set(node.transitions.map(it => it.next.version)) + ).toEqual( + new Set(expectedNode.transitions.map(it => it.next.version)) + ); + } } From 8152306a9239db579dcbf6cb30b0ba4f7dbb9236 Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Mon, 10 Mar 2025 21:59:12 +0100 Subject: [PATCH 128/180] test(backend): Testen voor DatabaseLearningPathProvider.searchLearningPath afgewerkt --- .../database-learning-path-provider.test.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) rename backend/tests/services/{learning-objects => learning-path}/database-learning-path-provider.test.ts (67%) diff --git a/backend/tests/services/learning-objects/database-learning-path-provider.test.ts b/backend/tests/services/learning-path/database-learning-path-provider.test.ts similarity index 67% rename from backend/tests/services/learning-objects/database-learning-path-provider.test.ts rename to backend/tests/services/learning-path/database-learning-path-provider.test.ts index 321fe213..5d612f04 100644 --- a/backend/tests/services/learning-objects/database-learning-path-provider.test.ts +++ b/backend/tests/services/learning-path/database-learning-path-provider.test.ts @@ -62,4 +62,32 @@ describe("DatabaseLearningPathProvider", () => { expect(result.success).toBe(false); }); }); + + describe("searchLearningPaths", () => { + it("returns the correct learning path when queried with a substring of its title", async () => { + const result = await databaseLearningPathProvider.searchLearningPaths( + example.learningPath.title.substring(2, 6), + example.learningPath.language + ); + expect(result.length).toBe(1); + expect(result[0].title).toBe(example.learningPath.title); + expect(result[0].description).toBe(example.learningPath.description); + }); + it("returns the correct learning path when queried with a substring of the description", async () => { + const result = await databaseLearningPathProvider.searchLearningPaths( + example.learningPath.description.substring(5, 12), + example.learningPath.language + ); + expect(result.length).toBe(1); + expect(result[0].title).toBe(example.learningPath.title); + expect(result[0].description).toBe(example.learningPath.description); + }); + it("returns an empty result when queried with a text which is not a substring of the title or the description of a learning path", async () => { + const result = await databaseLearningPathProvider.searchLearningPaths( + "substring which does not occur in the title or the description of a learning object", + example.learningPath.language + ); + expect(result.length).toBe(0); + }); + }); }); From cb6056e9d7487ccc5ab6655e4416095c4ebc35eb Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Mon, 10 Mar 2025 22:30:54 +0100 Subject: [PATCH 129/180] test(backend): Testen voor LearningObjectService toegevoegd --- backend/src/interfaces/learning-content.ts | 2 +- .../dwengo-api-learning-object-provider.ts | 2 +- .../learning-object-service.test.ts | 80 +++++++++++++++++++ 3 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 backend/tests/services/learning-objects/learning-object-service.test.ts diff --git a/backend/src/interfaces/learning-content.ts b/backend/src/interfaces/learning-content.ts index 89a1340c..5d11d6b2 100644 --- a/backend/src/interfaces/learning-content.ts +++ b/backend/src/interfaces/learning-content.ts @@ -65,7 +65,7 @@ export interface LearningObjectMetadata { uuid: string; hruid: string; version: number; - language: string; + language: Language; title: string; description: string; difficulty: number; diff --git a/backend/src/services/learning-objects/dwengo-api-learning-object-provider.ts b/backend/src/services/learning-objects/dwengo-api-learning-object-provider.ts index bef08dfe..628f616c 100644 --- a/backend/src/services/learning-objects/dwengo-api-learning-object-provider.ts +++ b/backend/src/services/learning-objects/dwengo-api-learning-object-provider.ts @@ -107,7 +107,7 @@ const dwengoApiLearningObjectProvider: LearningObjectProvider = { } ); - if (!metadata) { + if (!metadata || typeof metadata !== "object") { console.error(`⚠️ WARNING: Learning object "${id.hruid}" not found.`); return null; } diff --git a/backend/tests/services/learning-objects/learning-object-service.test.ts b/backend/tests/services/learning-objects/learning-object-service.test.ts new file mode 100644 index 00000000..2c2efd1a --- /dev/null +++ b/backend/tests/services/learning-objects/learning-object-service.test.ts @@ -0,0 +1,80 @@ +import {beforeAll, describe, expect, it} from "vitest"; +import {setupTestApp} from "../../setup-tests"; +import {LearningObject} from "../../../src/entities/content/learning-object.entity"; +import {getLearningObjectRepository} from "../../../src/data/repositories"; +import learningObjectExample from "../../test-assets/learning-objects/pn_werkingnotebooks/pn-werkingnotebooks-example"; +import learningObjectService from "../../../src/services/learning-objects/learning-object-service"; +import {LearningObjectIdentifier} from "../../../src/interfaces/learning-content"; +import {Language} from "../../../src/entities/content/language"; +import {EnvVars, getEnvVar} from "../../../src/util/envvars"; + +const TEST_LEARNING_OBJECT_TITLE = "Test title"; +const EXPECTED_DWENGO_LEARNING_OBJECT_TITLE = "Werken met notebooks"; +const DWENGO_TEST_LEARNING_OBJECT_ID: LearningObjectIdentifier = { + hruid: "pn_werkingnotebooks", + language: Language.Dutch, + version: 3 +}; + +async function initExampleData(): Promise { + const learningObjectRepo = getLearningObjectRepository(); + let learningObject = learningObjectExample.createLearningObject(); + learningObject.title = TEST_LEARNING_OBJECT_TITLE + await learningObjectRepo.save(learningObject); + return learningObject; +} + +describe("LearningObjectService", () => { + let exampleLearningObject: LearningObject; + + beforeAll(async () => { + await setupTestApp(); + exampleLearningObject = await initExampleData(); + }); + + describe("getLearningObjectById", () => { + it("returns the learning object from the Dwengo API if it does not have the user content prefix", async () => { + const result = await learningObjectService.getLearningObjectById(DWENGO_TEST_LEARNING_OBJECT_ID); + expect(result).not.toBeNull(); + expect(result?.title).toBe(EXPECTED_DWENGO_LEARNING_OBJECT_TITLE); + }); + it("returns the learning object from the database if it does have the user content prefix", async () => { + const result = await learningObjectService.getLearningObjectById(exampleLearningObject); + expect(result).not.toBeNull(); + expect(result?.title).toBe(exampleLearningObject.title); + }); + it("returns null if the hruid does not have the user content prefix and does not exist in the Dwengo repo", async () => { + const result = await learningObjectService.getLearningObjectById({ + hruid: "non-existing", + language: Language.Dutch + }); + expect(result).toBeNull(); + }); + }); + + describe("getLearningObjectHTML", () => { + it("returns the expected HTML when queried with the identifier of a learning object saved in the database", async () => { + const result = await learningObjectService.getLearningObjectHTML(exampleLearningObject); + expect(result).not.toBeNull(); + expect(result).toEqual(learningObjectExample.getHTMLRendering()); + }); + it("returns the same HTML as the Dwengo API when queried with the identifier of a learning object that does " + + "not start with the user content prefix", async () => { + const result = await learningObjectService.getLearningObjectHTML(DWENGO_TEST_LEARNING_OBJECT_ID); + expect(result).not.toBeNull(); + + const htmlFromDwengoApi = await fetch( + getEnvVar(EnvVars.LearningContentRepoApiBaseUrl) + + `/learningObject/getRaw?hruid=${DWENGO_TEST_LEARNING_OBJECT_ID.hruid}&language=${DWENGO_TEST_LEARNING_OBJECT_ID.language}&version=${DWENGO_TEST_LEARNING_OBJECT_ID.version}` + ).then(it => it.text()); + expect(result).toEqual(htmlFromDwengoApi); + }); + it("returns null when queried with a non-existing identifier", async () => { + const result = await learningObjectService.getLearningObjectHTML({ + hruid: "non_existing_hruid", + language: Language.Dutch + }); + expect(result).toBeNull(); + }); + }); +}); From 392510db8290482358bb18a51c289ad36a6dbb9b Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Mon, 10 Mar 2025 23:32:22 +0100 Subject: [PATCH 130/180] test(backend): Testen voor LearningPathService toegevoegd --- .../learning-paths/learning-path-service.ts | 2 +- .../content/attachment-repository.test.ts | 2 +- .../learning-object-repository.test.ts | 2 +- .../database-learning-object-provider.test.ts | 2 +- .../learning-object-service.test.ts | 4 +- .../database-learning-path-provider.test.ts | 2 +- .../learning-path-service.test.ts | 106 ++++++++++++++++++ .../Knop.png | Bin .../content.md | 0 .../dwengo.png | Bin .../pn-werkingnotebooks-example.ts | 2 +- .../rendering.html | 0 12 files changed, 114 insertions(+), 8 deletions(-) create mode 100644 backend/tests/services/learning-path/learning-path-service.test.ts rename backend/tests/test-assets/learning-objects/{pn_werkingnotebooks => pn-werkingnotebooks}/Knop.png (100%) rename backend/tests/test-assets/learning-objects/{pn_werkingnotebooks => pn-werkingnotebooks}/content.md (100%) rename backend/tests/test-assets/learning-objects/{pn_werkingnotebooks => pn-werkingnotebooks}/dwengo.png (100%) rename backend/tests/test-assets/learning-objects/{pn_werkingnotebooks => pn-werkingnotebooks}/pn-werkingnotebooks-example.ts (98%) rename backend/tests/test-assets/learning-objects/{pn_werkingnotebooks => pn-werkingnotebooks}/rendering.html (100%) diff --git a/backend/src/services/learning-paths/learning-path-service.ts b/backend/src/services/learning-paths/learning-path-service.ts index 601790c9..a00b4633 100644 --- a/backend/src/services/learning-paths/learning-path-service.ts +++ b/backend/src/services/learning-paths/learning-path-service.ts @@ -24,7 +24,7 @@ const learningPathService = { const userContentLearningPaths = await databaseLearningPathProvider.fetchLearningPaths(userContentHruids, language, source); const nonUserContentLearningPaths - = await databaseLearningPathProvider.fetchLearningPaths(nonUserContentHruids, language, source); + = await dwengoApiLearningPathProvider.fetchLearningPaths(nonUserContentHruids, language, source); return { data: (userContentLearningPaths.data || []).concat(nonUserContentLearningPaths.data || []), diff --git a/backend/tests/data/content/attachment-repository.test.ts b/backend/tests/data/content/attachment-repository.test.ts index 02727460..3f573cdb 100644 --- a/backend/tests/data/content/attachment-repository.test.ts +++ b/backend/tests/data/content/attachment-repository.test.ts @@ -3,7 +3,7 @@ import {setupTestApp} from "../../setup-tests"; import {getAttachmentRepository, getLearningObjectRepository} from "../../../src/data/repositories"; import {AttachmentRepository} from "../../../src/data/content/attachment-repository"; import {LearningObjectRepository} from "../../../src/data/content/learning-object-repository"; -import example from "../../test-assets/learning-objects/pn_werkingnotebooks/pn-werkingnotebooks-example"; +import example from "../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example"; import {LearningObject} from "../../../src/entities/content/learning-object.entity"; import {Attachment} from "../../../src/entities/content/attachment.entity"; import {LearningObjectIdentifier} from "../../../src/entities/content/learning-object-identifier"; diff --git a/backend/tests/data/content/learning-object-repository.test.ts b/backend/tests/data/content/learning-object-repository.test.ts index 87b8511e..bcca4c83 100644 --- a/backend/tests/data/content/learning-object-repository.test.ts +++ b/backend/tests/data/content/learning-object-repository.test.ts @@ -2,7 +2,7 @@ import {beforeAll, describe, it, expect} from "vitest"; import {LearningObjectRepository} from "../../../src/data/content/learning-object-repository"; import {setupTestApp} from "../../setup-tests"; import {getLearningObjectRepository} from "../../../src/data/repositories"; -import example from "../../test-assets/learning-objects/pn_werkingnotebooks/pn-werkingnotebooks-example.js" +import example from "../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.js" import {LearningObject} from "../../../src/entities/content/learning-object.entity"; import {expectToBeCorrectEntity} from "../../test-utils/expectations"; diff --git a/backend/tests/services/learning-objects/database-learning-object-provider.test.ts b/backend/tests/services/learning-objects/database-learning-object-provider.test.ts index c8783246..691b29ba 100644 --- a/backend/tests/services/learning-objects/database-learning-object-provider.test.ts +++ b/backend/tests/services/learning-objects/database-learning-object-provider.test.ts @@ -1,7 +1,7 @@ import {beforeAll, describe, expect, it} from "vitest"; import {setupTestApp} from "../../setup-tests"; import {getLearningObjectRepository} from "../../../src/data/repositories"; -import example from "../../test-assets/learning-objects/pn_werkingnotebooks/pn-werkingnotebooks-example"; +import example from "../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example"; import {LearningObject} from "../../../src/entities/content/learning-object.entity"; import databaseLearningObjectProvider from "../../../src/services/learning-objects/database-learning-object-provider"; import { diff --git a/backend/tests/services/learning-objects/learning-object-service.test.ts b/backend/tests/services/learning-objects/learning-object-service.test.ts index 2c2efd1a..2fac3d3e 100644 --- a/backend/tests/services/learning-objects/learning-object-service.test.ts +++ b/backend/tests/services/learning-objects/learning-object-service.test.ts @@ -2,7 +2,7 @@ import {beforeAll, describe, expect, it} from "vitest"; import {setupTestApp} from "../../setup-tests"; import {LearningObject} from "../../../src/entities/content/learning-object.entity"; import {getLearningObjectRepository} from "../../../src/data/repositories"; -import learningObjectExample from "../../test-assets/learning-objects/pn_werkingnotebooks/pn-werkingnotebooks-example"; +import learningObjectExample from "../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example"; import learningObjectService from "../../../src/services/learning-objects/learning-object-service"; import {LearningObjectIdentifier} from "../../../src/interfaces/learning-content"; import {Language} from "../../../src/entities/content/language"; @@ -11,7 +11,7 @@ import {EnvVars, getEnvVar} from "../../../src/util/envvars"; const TEST_LEARNING_OBJECT_TITLE = "Test title"; const EXPECTED_DWENGO_LEARNING_OBJECT_TITLE = "Werken met notebooks"; const DWENGO_TEST_LEARNING_OBJECT_ID: LearningObjectIdentifier = { - hruid: "pn_werkingnotebooks", + hruid: "pn-werkingnotebooks", language: Language.Dutch, version: 3 }; diff --git a/backend/tests/services/learning-path/database-learning-path-provider.test.ts b/backend/tests/services/learning-path/database-learning-path-provider.test.ts index 5d612f04..0d46c1e0 100644 --- a/backend/tests/services/learning-path/database-learning-path-provider.test.ts +++ b/backend/tests/services/learning-path/database-learning-path-provider.test.ts @@ -3,7 +3,7 @@ import {LearningObject} from "../../../src/entities/content/learning-object.enti import {setupTestApp} from "../../setup-tests"; import {LearningPath} from "../../../src/entities/content/learning-path.entity"; import {getLearningObjectRepository, getLearningPathRepository} from "../../../src/data/repositories"; -import learningObjectExample from "../../test-assets/learning-objects/pn_werkingnotebooks/pn-werkingnotebooks-example"; +import learningObjectExample from "../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example"; import learningPathExample from "../../test-assets/learning-paths/pn-werking-example" import databaseLearningPathProvider from "../../../src/services/learning-paths/database-learning-path-provider"; import {expectToBeCorrectLearningPath} from "../../test-utils/expectations"; diff --git a/backend/tests/services/learning-path/learning-path-service.test.ts b/backend/tests/services/learning-path/learning-path-service.test.ts new file mode 100644 index 00000000..83db1bef --- /dev/null +++ b/backend/tests/services/learning-path/learning-path-service.test.ts @@ -0,0 +1,106 @@ +import {beforeAll, describe, expect, it} from "vitest"; +import {setupTestApp} from "../../setup-tests"; +import {LearningObject} from "../../../src/entities/content/learning-object.entity"; +import {LearningPath} from "../../../src/entities/content/learning-path.entity"; +import {getLearningObjectRepository, getLearningPathRepository} from "../../../src/data/repositories"; +import learningObjectExample from "../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example"; +import learningPathExample from "../../test-assets/learning-paths/pn-werking-example"; +import {Language} from "../../../src/entities/content/language"; +import learningPathService from "../../../src/services/learning-paths/learning-path-service"; + +async function initExampleData(): Promise<{ learningObject: LearningObject, learningPath: LearningPath }> { + const learningObjectRepo = getLearningObjectRepository(); + const learningPathRepo = getLearningPathRepository(); + let learningObject = learningObjectExample.createLearningObject(); + let learningPath = learningPathExample.createLearningPath(); + await learningObjectRepo.save(learningObject); + await learningPathRepo.save(learningPath); + return { learningObject, learningPath }; +} + +const TEST_DWENGO_LEARNING_PATH_HRUID = "pn_werking"; +const TEST_DWENGO_LEARNING_PATH_TITLE = "Werken met notebooks"; +const TEST_DWENGO_EXCLUSIVE_LEARNING_PATH_SEARCH_QUERY = "Microscopie"; +const TEST_SEARCH_QUERY_EXPECTING_NO_MATCHES = "su$m8f9usf89ud { + let example: { learningObject: LearningObject, learningPath: LearningPath }; + beforeAll(async () => { + await setupTestApp(); + example = await initExampleData(); + }); + describe("fetchLearningPaths", () => { + it("should return learning paths both from the database and from the Dwengo API", async () => { + const result = await learningPathService.fetchLearningPaths( + [example.learningPath.hruid, TEST_DWENGO_LEARNING_PATH_HRUID], + example.learningPath.language, + "the source" + ); + expect(result.success).toBeTruthy(); + expect(result.data?.filter(it => it.hruid == TEST_DWENGO_LEARNING_PATH_HRUID).length).not.toBe(0); + expect(result.data?.filter(it => it.hruid == example.learningPath.hruid).length).not.toBe(0); + expect(result.data?.filter(it => it.hruid == TEST_DWENGO_LEARNING_PATH_HRUID)[0].title) + .toEqual(TEST_DWENGO_LEARNING_PATH_TITLE); + expect(result.data?.filter(it => it.hruid == example.learningPath.hruid)[0].title) + .toEqual(example.learningPath.title); + }); + it("should include both the learning objects from the Dwengo API and learning objects from the database in its response", async () => { + const result = await learningPathService.fetchLearningPaths( + [example.learningPath.hruid], + example.learningPath.language, + "the source" + ); + expect(result.success).toBeTruthy(); + expect(result.data?.length).toBe(1); + + // Should include all the nodes, even those pointing to foreign learning objects. + expect( + [...result.data![0].nodes.map(it => it.learningobject_hruid)].sort() + ).toEqual( + example.learningPath.nodes.map(it => it.learningObjectHruid).sort() + ); + }); + }); + describe("searchLearningPath", () => { + it("should include both the learning paths from the Dwengo API and those from the database in its response", async () => { + // This matches the learning object in the database, but definitely also some learning objects in the Dwengo API. + const result = await learningPathService.searchLearningPaths( + example.learningPath.title.substring(2, 3), + example.learningPath.language + ); + + // Should find the one from the database + expect( + result.filter(it => + it.hruid === example.learningPath.hruid && it.title === example.learningPath.title + ).length + ).toBe(1); + + // but should not only find that one. + expect(result.length).not.toBeLessThan(2); + }); + it("should still return results from the Dwengo API even though there are no matches in the database", async () => { + const result = await learningPathService.searchLearningPaths( + TEST_DWENGO_EXCLUSIVE_LEARNING_PATH_SEARCH_QUERY, + Language.Dutch + ); + + // Should find something... + expect(result.length).not.toBe(0); + + // but not the example learning path. + expect( + result.filter(it => + it.hruid === example.learningPath.hruid && it.title === example.learningPath.title + ).length + ).toBe(0); + }); + it("should return an empty list if neither the Dwengo API nor the database contains matches", async () => { + const result = await learningPathService.searchLearningPaths( + TEST_SEARCH_QUERY_EXPECTING_NO_MATCHES, + Language.Dutch + ); + expect(result.length).toBe(0); + }); + }); +}); diff --git a/backend/tests/test-assets/learning-objects/pn_werkingnotebooks/Knop.png b/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/Knop.png similarity index 100% rename from backend/tests/test-assets/learning-objects/pn_werkingnotebooks/Knop.png rename to backend/tests/test-assets/learning-objects/pn-werkingnotebooks/Knop.png diff --git a/backend/tests/test-assets/learning-objects/pn_werkingnotebooks/content.md b/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/content.md similarity index 100% rename from backend/tests/test-assets/learning-objects/pn_werkingnotebooks/content.md rename to backend/tests/test-assets/learning-objects/pn-werkingnotebooks/content.md diff --git a/backend/tests/test-assets/learning-objects/pn_werkingnotebooks/dwengo.png b/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/dwengo.png similarity index 100% rename from backend/tests/test-assets/learning-objects/pn_werkingnotebooks/dwengo.png rename to backend/tests/test-assets/learning-objects/pn-werkingnotebooks/dwengo.png diff --git a/backend/tests/test-assets/learning-objects/pn_werkingnotebooks/pn-werkingnotebooks-example.ts b/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.ts similarity index 98% rename from backend/tests/test-assets/learning-objects/pn_werkingnotebooks/pn-werkingnotebooks-example.ts rename to backend/tests/test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.ts index 4dff2c34..09cab0f9 100644 --- a/backend/tests/test-assets/learning-objects/pn_werkingnotebooks/pn-werkingnotebooks-example.ts +++ b/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.ts @@ -6,7 +6,7 @@ import {EducationalGoal, LearningObject, ReturnValue} from "../../../../src/enti import {Attachment} from "../../../../src/entities/content/attachment.entity"; import {EnvVars, getEnvVar} from "../../../../src/util/envvars"; -const ASSETS_PREFIX = "learning-objects/pn_werkingnotebooks/"; +const ASSETS_PREFIX = "learning-objects/pn-werkingnotebooks/"; const example: LearningObjectExample = { createLearningObject: ()=> { diff --git a/backend/tests/test-assets/learning-objects/pn_werkingnotebooks/rendering.html b/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/rendering.html similarity index 100% rename from backend/tests/test-assets/learning-objects/pn_werkingnotebooks/rendering.html rename to backend/tests/test-assets/learning-objects/pn-werkingnotebooks/rendering.html From 385f4ae569dade14a730593603577dd1b36b14e3 Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Mon, 10 Mar 2025 23:35:53 +0100 Subject: [PATCH 131/180] fix(backend): Per ongeluk gemaakte aanpassing ongedaan gemaakt. (De '_' in DWENGO_TEST_LEARNING_OBJECT_ID (learning-object-service.test.ts) moest wel degelijk een '_' blijven en geen '-' worden.) --- .../services/learning-objects/learning-object-service.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/tests/services/learning-objects/learning-object-service.test.ts b/backend/tests/services/learning-objects/learning-object-service.test.ts index 2fac3d3e..970e4675 100644 --- a/backend/tests/services/learning-objects/learning-object-service.test.ts +++ b/backend/tests/services/learning-objects/learning-object-service.test.ts @@ -11,7 +11,7 @@ import {EnvVars, getEnvVar} from "../../../src/util/envvars"; const TEST_LEARNING_OBJECT_TITLE = "Test title"; const EXPECTED_DWENGO_LEARNING_OBJECT_TITLE = "Werken met notebooks"; const DWENGO_TEST_LEARNING_OBJECT_ID: LearningObjectIdentifier = { - hruid: "pn-werkingnotebooks", + hruid: "pn_werkingnotebooks", language: Language.Dutch, version: 3 }; From 050c83ca33550d293533e29c3f3788db434aedfb Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Mon, 10 Mar 2025 23:55:16 +0100 Subject: [PATCH 132/180] test(backend): Test-meerkeuzevraag toegevoegd. --- .../test-multiple-choice/content.txt | 5 +++++ .../test-multiple-choice/rendering.html | 0 .../test-multiple-choice-example.ts | 22 +++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 backend/tests/test-assets/learning-objects/test-multiple-choice/content.txt create mode 100644 backend/tests/test-assets/learning-objects/test-multiple-choice/rendering.html create mode 100644 backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts diff --git a/backend/tests/test-assets/learning-objects/test-multiple-choice/content.txt b/backend/tests/test-assets/learning-objects/test-multiple-choice/content.txt new file mode 100644 index 00000000..7dd5527d --- /dev/null +++ b/backend/tests/test-assets/learning-objects/test-multiple-choice/content.txt @@ -0,0 +1,5 @@ +::MC basic:: +Are you following along well with the class? { + ~No, it's very difficult to follow along. + =Yes, no problem! +} diff --git a/backend/tests/test-assets/learning-objects/test-multiple-choice/rendering.html b/backend/tests/test-assets/learning-objects/test-multiple-choice/rendering.html new file mode 100644 index 00000000..e69de29b diff --git a/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts b/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts new file mode 100644 index 00000000..141a0411 --- /dev/null +++ b/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts @@ -0,0 +1,22 @@ +import {LearningObjectExample} from "../learning-object-example"; +import {LearningObject} from "../../../../src/entities/content/learning-object.entity"; +import {loadTestAsset} from "../../../test-utils/load-test-asset"; +import {EnvVars, getEnvVar} from "../../../../src/util/envvars"; +import {Language} from "../../../../src/entities/content/language"; + +const example: LearningObjectExample = { + createLearningObject: () => { + const learningObject = new LearningObject(); + learningObject.hruid = `${getEnvVar(EnvVars.UserContentPrefix)}test_multiple_choice`; + learningObject.language = Language.English; + learningObject.version = 1; + learningObject.title = "Multiple choice question for testing"; + learningObject.description = "This multiple choice question was only created for testing purposes."; + learningObject.content = loadTestAsset("learning-objects/test-multiple-choice/content.txt"); + return learningObject; + }, + createAttachment: {}, + getHTMLRendering: () => loadTestAsset("learning-objects/test-multiple-choice/rendering.html").toString() +}; + +export default example; From 164a547dd1031ebb4959d76ec80d7c82367f7714 Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Tue, 11 Mar 2025 00:54:06 +0100 Subject: [PATCH 133/180] test(backend): Testdata voor voorwaardelijke overgangen toegevoegd --- .../learning-path-personalizing-service.ts | 5 ++ .../dummy/dummy-learning-object-example.ts | 25 +++++++ .../learning-objects/dummy/rendering.html | 0 .../learning-paths/test-conditions-example.ts | 74 +++++++++++++++++++ 4 files changed, 104 insertions(+) create mode 100644 backend/src/services/learning-paths/learning-path-personalizing-service.ts create mode 100644 backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts create mode 100644 backend/tests/test-assets/learning-objects/dummy/rendering.html create mode 100644 backend/tests/test-assets/learning-paths/test-conditions-example.ts diff --git a/backend/src/services/learning-paths/learning-path-personalizing-service.ts b/backend/src/services/learning-paths/learning-path-personalizing-service.ts new file mode 100644 index 00000000..2341cc60 --- /dev/null +++ b/backend/src/services/learning-paths/learning-path-personalizing-service.ts @@ -0,0 +1,5 @@ +const learningPathPersonalizingService = { + +}; + +export default learningPathPersonalizingService; diff --git a/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts b/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts new file mode 100644 index 00000000..cb0f3d45 --- /dev/null +++ b/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts @@ -0,0 +1,25 @@ +import {LearningObjectExample} from "../learning-object-example"; +import {LearningObject} from "../../../../src/entities/content/learning-object.entity"; +import {Language} from "../../../../src/entities/content/language"; +import {loadTestAsset} from "../../../test-utils/load-test-asset"; + +/** + * Create a dummy learning object to be used in tests where multiple learning objects are needed (for example for use + * on a path), but where the precise contents of the learning object are not important. + */ +export function dummyLearningObject(hruid: string, language: Language, title: string): LearningObjectExample { + return { + createLearningObject: () => { + const learningObject = new LearningObject(); + learningObject.hruid = hruid; + learningObject.language = language; + learningObject.version = 1; + learningObject.title = title; + learningObject.description = "Just a dummy learning object for testing purposes"; + learningObject.content = Buffer.from("Dummy content"); + return learningObject; + }, + createAttachment: {}, + getHTMLRendering: () => loadTestAsset("learning-objects/dummy/rendering.html").toString() + } +} diff --git a/backend/tests/test-assets/learning-objects/dummy/rendering.html b/backend/tests/test-assets/learning-objects/dummy/rendering.html new file mode 100644 index 00000000..e69de29b diff --git a/backend/tests/test-assets/learning-paths/test-conditions-example.ts b/backend/tests/test-assets/learning-paths/test-conditions-example.ts new file mode 100644 index 00000000..000bb732 --- /dev/null +++ b/backend/tests/test-assets/learning-paths/test-conditions-example.ts @@ -0,0 +1,74 @@ +import {LearningPath} from "../../../src/entities/content/learning-path.entity"; +import {Language} from "../../../src/entities/content/language"; +import testMultipleChoiceExample from "../learning-objects/test-multiple-choice/test-multiple-choice-example"; +import {dummyLearningObject} from "../learning-objects/dummy/dummy-learning-object-example"; +import {createLearningPathNode, createLearningPathTransition} from "./learning-path-utils"; + +const example: LearningPathExample = { + createLearningPath: () => { + const learningPath = new LearningPath(); + learningPath.hruid = "test_conditions"; + learningPath.language = Language.English; + learningPath.title = "Example learning path with conditional transitions"; + learningPath.description = "This learning path was made for the purpose of testing conditional transitions"; + + const branchingLearningObject = testMultipleChoiceExample.createLearningObject(); + const extraExerciseLearningObject = dummyLearningObject( + "test_extra_exercise", Language.English, "Extra exercise (for students with difficulties)" + ).createLearningObject(); + const finalLearningObject = dummyLearningObject( + "test_final_learning_object", Language.English, "Final exercise (for everyone)" + ).createLearningObject(); + + const branchingNode = createLearningPathNode( + learningPath, + 0, + branchingLearningObject.hruid, + branchingLearningObject.version, + branchingLearningObject.language, + true + ); + const extraExerciseNode = createLearningPathNode( + learningPath, + 1, + extraExerciseLearningObject.hruid, + extraExerciseLearningObject.version, + extraExerciseLearningObject.language, + false + ); + const finalNode = createLearningPathNode( + learningPath, + 2, + finalLearningObject.hruid, + finalLearningObject.version, + finalLearningObject.language, + false + ); + + const transitionToExtraExercise = createLearningPathTransition( + branchingNode, + 0, + "$[?(@[0] == 0)]", // The answer to the first question was the first one, which says that it is difficult for the student to follow along. + extraExerciseNode + ); + const directTransitionToFinal = createLearningPathTransition( + branchingNode, + 1, + "$[?(@[0] == 1)]", + finalNode + ); + const transitionExtraExerciseToFinal = createLearningPathTransition( + extraExerciseNode, + 0, + "true", + finalNode + ); + + branchingNode.transitions = [transitionToExtraExercise, directTransitionToFinal]; + extraExerciseNode.transitions = [transitionExtraExerciseToFinal]; + + learningPath.nodes = [branchingNode, extraExerciseNode, finalNode]; + + return learningPath; + } +}; From bc0ac63c92d16a402174662cd7e88b91321a65da Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Tue, 11 Mar 2025 02:00:27 +0100 Subject: [PATCH 134/180] feat(backend): Rendering van meerkeuzevragen en open vragen (essay) toegevoegd + getest --- .../processing/audio/audio-processor.ts | 2 ++ .../processing/extern/extern-processor.ts | 2 ++ .../processing/gift/gift-processor.ts | 14 +++++++---- .../category-question-renderer.ts | 2 +- .../description-question-renderer.ts | 2 +- .../essay-question-renderer.ts | 12 +++++++-- .../gift-question-renderer.ts | 3 ++- .../matching-question-renderer.ts | 2 +- .../multiple-choice-question-renderer.ts | 19 ++++++++++++-- .../numerical-question-renderer.ts | 2 +- .../short-question-renderer.ts | 2 +- .../true-false-question-renderer.ts | 2 +- .../processing/pdf/pdf-processor.ts | 2 ++ .../processing/processing-service.test.ts | 25 +++++++++++++++++++ .../dummy/dummy-learning-object-example.ts | 2 ++ .../learning-objects/test-essay/content.txt | 2 ++ .../test-essay/rendering.html | 7 ++++++ .../test-essay/test-essay-example.ts | 24 ++++++++++++++++++ .../test-multiple-choice/rendering.html | 14 +++++++++++ .../test-multiple-choice-example.ts | 2 ++ 20 files changed, 126 insertions(+), 16 deletions(-) create mode 100644 backend/tests/services/learning-objects/processing/processing-service.test.ts create mode 100644 backend/tests/test-assets/learning-objects/test-essay/content.txt create mode 100644 backend/tests/test-assets/learning-objects/test-essay/rendering.html create mode 100644 backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts diff --git a/backend/src/services/learning-objects/processing/audio/audio-processor.ts b/backend/src/services/learning-objects/processing/audio/audio-processor.ts index 6442e1b3..0c4dd75e 100644 --- a/backend/src/services/learning-objects/processing/audio/audio-processor.ts +++ b/backend/src/services/learning-objects/processing/audio/audio-processor.ts @@ -1,5 +1,7 @@ /** * Based on https://github.com/dwengovzw/Learning-Object-Repository/blob/main/app/processors/audio/audio_processor.js + * + * WARNING: The support for audio learning objects is currently still experimental. */ import DOMPurify from 'isomorphic-dompurify'; diff --git a/backend/src/services/learning-objects/processing/extern/extern-processor.ts b/backend/src/services/learning-objects/processing/extern/extern-processor.ts index 2aa02482..aff26d45 100644 --- a/backend/src/services/learning-objects/processing/extern/extern-processor.ts +++ b/backend/src/services/learning-objects/processing/extern/extern-processor.ts @@ -1,5 +1,7 @@ /** * Based on https://github.com/dwengovzw/Learning-Object-Repository/blob/main/app/processors/extern/extern_processor.js + * + * WARNING: The support for external content is currently still experimental. */ import DOMPurify from 'isomorphic-dompurify'; diff --git a/backend/src/services/learning-objects/processing/gift/gift-processor.ts b/backend/src/services/learning-objects/processing/gift/gift-processor.ts index 5cffcb47..5d20e99c 100644 --- a/backend/src/services/learning-objects/processing/gift/gift-processor.ts +++ b/backend/src/services/learning-objects/processing/gift/gift-processor.ts @@ -36,18 +36,22 @@ class GiftProcessor extends StringProcessor { override renderFn(giftString: string) { const quizQuestions: GIFTQuestion[] = parse(giftString); - let html = "
"; + let html = "
\n"; + let i = 1; for (let question of quizQuestions) { - html += this.renderQuestion(question); + html += `
\n`; + html += " " + this.renderQuestion(question, i).replaceAll(/\n(.+)/g, "\n $1"); // replace for indentation. + html += `
\n`; + i++; } - html += "
" + html += "
\n" return DOMPurify.sanitize(html); } - private renderQuestion(question: T): string { + private renderQuestion(question: T, questionNumber: number): string { const renderer = this.renderers[question.type] as GIFTQuestionRenderer; - return renderer.render(question); + return renderer.render(question, questionNumber); } } diff --git a/backend/src/services/learning-objects/processing/gift/question-renderers/category-question-renderer.ts b/backend/src/services/learning-objects/processing/gift/question-renderers/category-question-renderer.ts index 8329d4d6..6f299c17 100644 --- a/backend/src/services/learning-objects/processing/gift/question-renderers/category-question-renderer.ts +++ b/backend/src/services/learning-objects/processing/gift/question-renderers/category-question-renderer.ts @@ -3,7 +3,7 @@ import {Category} from "gift-pegjs"; import {ProcessingError} from "../../processing-error"; export class CategoryQuestionRenderer extends GIFTQuestionRenderer { - render(question: Category): string { + render(question: Category, questionNumber: number): string { throw new ProcessingError("The question type 'Category' is not supported yet!"); } } diff --git a/backend/src/services/learning-objects/processing/gift/question-renderers/description-question-renderer.ts b/backend/src/services/learning-objects/processing/gift/question-renderers/description-question-renderer.ts index 1f8c94be..adea25a6 100644 --- a/backend/src/services/learning-objects/processing/gift/question-renderers/description-question-renderer.ts +++ b/backend/src/services/learning-objects/processing/gift/question-renderers/description-question-renderer.ts @@ -3,7 +3,7 @@ import {Description} from "gift-pegjs"; import {ProcessingError} from "../../processing-error"; export class DescriptionQuestionRenderer extends GIFTQuestionRenderer { - render(question: Description): string { + render(question: Description, questionNumber: number): string { throw new ProcessingError("The question type 'Description' is not supported yet!"); } } diff --git a/backend/src/services/learning-objects/processing/gift/question-renderers/essay-question-renderer.ts b/backend/src/services/learning-objects/processing/gift/question-renderers/essay-question-renderer.ts index e990d000..af000c11 100644 --- a/backend/src/services/learning-objects/processing/gift/question-renderers/essay-question-renderer.ts +++ b/backend/src/services/learning-objects/processing/gift/question-renderers/essay-question-renderer.ts @@ -2,7 +2,15 @@ import {GIFTQuestionRenderer} from "./gift-question-renderer"; import {Essay} from "gift-pegjs"; export class EssayQuestionRenderer extends GIFTQuestionRenderer { - render(question: Essay): string { - return ""; + render(question: Essay, questionNumber: number): string { + let renderedHtml = ""; + if (question.title) { + renderedHtml += `

${question.title}

\n`; + } + if (question.stem) { + renderedHtml += `

${question.stem.text}

\n`; + } + renderedHtml += `\n`; + return renderedHtml; } } diff --git a/backend/src/services/learning-objects/processing/gift/question-renderers/gift-question-renderer.ts b/backend/src/services/learning-objects/processing/gift/question-renderers/gift-question-renderer.ts index 8b91185b..bd33107b 100644 --- a/backend/src/services/learning-objects/processing/gift/question-renderers/gift-question-renderer.ts +++ b/backend/src/services/learning-objects/processing/gift/question-renderers/gift-question-renderer.ts @@ -7,7 +7,8 @@ export abstract class GIFTQuestionRenderer { /** * Render the given question to HTML. * @param question The question. + * @param questionNumber The index number of the question. * @returns The question rendered as HTML. */ - abstract render(question: T): string; + abstract render(question: T, questionNumber: number): string; } diff --git a/backend/src/services/learning-objects/processing/gift/question-renderers/matching-question-renderer.ts b/backend/src/services/learning-objects/processing/gift/question-renderers/matching-question-renderer.ts index e9a2deaf..93e7511e 100644 --- a/backend/src/services/learning-objects/processing/gift/question-renderers/matching-question-renderer.ts +++ b/backend/src/services/learning-objects/processing/gift/question-renderers/matching-question-renderer.ts @@ -3,7 +3,7 @@ import {Matching} from "gift-pegjs"; import {ProcessingError} from "../../processing-error"; export class MatchingQuestionRenderer extends GIFTQuestionRenderer { - render(question: Matching): string { + render(question: Matching, questionNumber: number): string { throw new ProcessingError("The question type 'Matching' is not supported yet!"); } } diff --git a/backend/src/services/learning-objects/processing/gift/question-renderers/multiple-choice-question-renderer.ts b/backend/src/services/learning-objects/processing/gift/question-renderers/multiple-choice-question-renderer.ts index 2c40ff25..6b6d8eea 100644 --- a/backend/src/services/learning-objects/processing/gift/question-renderers/multiple-choice-question-renderer.ts +++ b/backend/src/services/learning-objects/processing/gift/question-renderers/multiple-choice-question-renderer.ts @@ -2,7 +2,22 @@ import {GIFTQuestionRenderer} from "./gift-question-renderer"; import {MultipleChoice} from "gift-pegjs"; export class MultipleChoiceQuestionRenderer extends GIFTQuestionRenderer { - render(question: MultipleChoice): string { - return ""; + render(question: MultipleChoice, questionNumber: number): string { + let renderedHtml = ""; + if (question.title) { + renderedHtml += `

${question.title}

\n`; + } + if (question.stem) { + renderedHtml += `

${question.stem.text}

\n`; + } + let i = 0; + for (let choice of question.choices) { + renderedHtml += `
\n`; + renderedHtml += ` \n`; + renderedHtml += ` \n`; + renderedHtml += `
\n`; + i++; + } + return renderedHtml; } } diff --git a/backend/src/services/learning-objects/processing/gift/question-renderers/numerical-question-renderer.ts b/backend/src/services/learning-objects/processing/gift/question-renderers/numerical-question-renderer.ts index 5da3fafd..6553add4 100644 --- a/backend/src/services/learning-objects/processing/gift/question-renderers/numerical-question-renderer.ts +++ b/backend/src/services/learning-objects/processing/gift/question-renderers/numerical-question-renderer.ts @@ -3,7 +3,7 @@ import {Numerical} from "gift-pegjs"; import {ProcessingError} from "../../processing-error"; export class NumericalQuestionRenderer extends GIFTQuestionRenderer { - render(question: Numerical): string { + render(question: Numerical, questionNumber: number): string { throw new ProcessingError("The question type 'Numerical' is not supported yet!"); } } diff --git a/backend/src/services/learning-objects/processing/gift/question-renderers/short-question-renderer.ts b/backend/src/services/learning-objects/processing/gift/question-renderers/short-question-renderer.ts index be3c9365..96196a67 100644 --- a/backend/src/services/learning-objects/processing/gift/question-renderers/short-question-renderer.ts +++ b/backend/src/services/learning-objects/processing/gift/question-renderers/short-question-renderer.ts @@ -3,7 +3,7 @@ import {ShortAnswer} from "gift-pegjs"; import {ProcessingError} from "../../processing-error"; export class ShortQuestionRenderer extends GIFTQuestionRenderer { - render(question: ShortAnswer): string { + render(question: ShortAnswer, questionNumber: number): string { throw new ProcessingError("The question type 'ShortAnswer' is not supported yet!"); } } diff --git a/backend/src/services/learning-objects/processing/gift/question-renderers/true-false-question-renderer.ts b/backend/src/services/learning-objects/processing/gift/question-renderers/true-false-question-renderer.ts index 668ee3de..0ff108f4 100644 --- a/backend/src/services/learning-objects/processing/gift/question-renderers/true-false-question-renderer.ts +++ b/backend/src/services/learning-objects/processing/gift/question-renderers/true-false-question-renderer.ts @@ -3,7 +3,7 @@ import {TrueFalse} from "gift-pegjs"; import {ProcessingError} from "../../processing-error"; export class TrueFalseQuestionRenderer extends GIFTQuestionRenderer { - render(question: TrueFalse): string { + render(question: TrueFalse, questionNumber: number): string { throw new ProcessingError("The question type 'TrueFalse' is not supported yet!"); } } diff --git a/backend/src/services/learning-objects/processing/pdf/pdf-processor.ts b/backend/src/services/learning-objects/processing/pdf/pdf-processor.ts index fe05077e..dcb08ba7 100644 --- a/backend/src/services/learning-objects/processing/pdf/pdf-processor.ts +++ b/backend/src/services/learning-objects/processing/pdf/pdf-processor.ts @@ -1,5 +1,7 @@ /** * Based on https://github.com/dwengovzw/Learning-Object-Repository/blob/main/app/processors/pdf/pdf_processor.js + * + * WARNING: The support for PDF learning objects is currently still experimental. */ import DOMPurify from 'isomorphic-dompurify'; diff --git a/backend/tests/services/learning-objects/processing/processing-service.test.ts b/backend/tests/services/learning-objects/processing/processing-service.test.ts new file mode 100644 index 00000000..f0107162 --- /dev/null +++ b/backend/tests/services/learning-objects/processing/processing-service.test.ts @@ -0,0 +1,25 @@ +import {describe, expect, it} from "vitest"; +import mdExample from "../../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example"; +import multipleChoiceExample from "../../../test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example"; +import essayExample from "../../../test-assets/learning-objects/test-essay/test-essay-example"; +import processingService from "../../../../src/services/learning-objects/processing/processing-service"; + +describe("ProcessingService", () => { + it("renders a markdown learning object correctly", async () => { + const markdownLearningObject = mdExample.createLearningObject(); + const result = await processingService.render(markdownLearningObject); + expect(result).toEqual(mdExample.getHTMLRendering()); + }); + + it("renders a multiple choice question correctly", async () => { + const multipleChoiceLearningObject = multipleChoiceExample.createLearningObject(); + const result = await processingService.render(multipleChoiceLearningObject); + expect(result).toEqual(multipleChoiceExample.getHTMLRendering()); + }); + + it("renders an essay question correctly", async () => { + const essayLearningObject = essayExample.createLearningObject(); + const result = await processingService.render(essayLearningObject); + expect(result).toEqual(essayExample.getHTMLRendering()); + }); +}); diff --git a/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts b/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts index cb0f3d45..dfc15a7a 100644 --- a/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts +++ b/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts @@ -2,6 +2,7 @@ import {LearningObjectExample} from "../learning-object-example"; import {LearningObject} from "../../../../src/entities/content/learning-object.entity"; import {Language} from "../../../../src/entities/content/language"; import {loadTestAsset} from "../../../test-utils/load-test-asset"; +import {DwengoContentType} from "../../../../src/services/learning-objects/processing/content-type"; /** * Create a dummy learning object to be used in tests where multiple learning objects are needed (for example for use @@ -16,6 +17,7 @@ export function dummyLearningObject(hruid: string, language: Language, title: st learningObject.version = 1; learningObject.title = title; learningObject.description = "Just a dummy learning object for testing purposes"; + learningObject.contentType = DwengoContentType.TEXT_PLAIN; learningObject.content = Buffer.from("Dummy content"); return learningObject; }, diff --git a/backend/tests/test-assets/learning-objects/test-essay/content.txt b/backend/tests/test-assets/learning-objects/test-essay/content.txt new file mode 100644 index 00000000..dd6b5c77 --- /dev/null +++ b/backend/tests/test-assets/learning-objects/test-essay/content.txt @@ -0,0 +1,2 @@ +::MC basic:: +How are you? {} diff --git a/backend/tests/test-assets/learning-objects/test-essay/rendering.html b/backend/tests/test-assets/learning-objects/test-essay/rendering.html new file mode 100644 index 00000000..adb072a0 --- /dev/null +++ b/backend/tests/test-assets/learning-objects/test-essay/rendering.html @@ -0,0 +1,7 @@ +
+
+

MC basic

+

How are you?

+ +
+
diff --git a/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts b/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts new file mode 100644 index 00000000..08a818f7 --- /dev/null +++ b/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts @@ -0,0 +1,24 @@ +import {LearningObjectExample} from "../learning-object-example"; +import {LearningObject} from "../../../../src/entities/content/learning-object.entity"; +import {loadTestAsset} from "../../../test-utils/load-test-asset"; +import {EnvVars, getEnvVar} from "../../../../src/util/envvars"; +import {Language} from "../../../../src/entities/content/language"; +import {DwengoContentType} from "../../../../src/services/learning-objects/processing/content-type"; + +const example: LearningObjectExample = { + createLearningObject: () => { + const learningObject = new LearningObject(); + learningObject.hruid = `${getEnvVar(EnvVars.UserContentPrefix)}test_essay`; + learningObject.language = Language.English; + learningObject.version = 1; + learningObject.title = "Essay question for testing"; + learningObject.description = "This essay question was only created for testing purposes."; + learningObject.contentType = DwengoContentType.GIFT; + learningObject.content = loadTestAsset("learning-objects/test-essay/content.txt"); + return learningObject; + }, + createAttachment: {}, + getHTMLRendering: () => loadTestAsset("learning-objects/test-essay/rendering.html").toString() +}; + +export default example; diff --git a/backend/tests/test-assets/learning-objects/test-multiple-choice/rendering.html b/backend/tests/test-assets/learning-objects/test-multiple-choice/rendering.html index e69de29b..c1829f24 100644 --- a/backend/tests/test-assets/learning-objects/test-multiple-choice/rendering.html +++ b/backend/tests/test-assets/learning-objects/test-multiple-choice/rendering.html @@ -0,0 +1,14 @@ +
+
+

MC basic

+

Are you following along well with the class?

+
+ + +
+
+ + +
+
+
diff --git a/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts b/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts index 141a0411..6abc56dd 100644 --- a/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts +++ b/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts @@ -3,6 +3,7 @@ import {LearningObject} from "../../../../src/entities/content/learning-object.e import {loadTestAsset} from "../../../test-utils/load-test-asset"; import {EnvVars, getEnvVar} from "../../../../src/util/envvars"; import {Language} from "../../../../src/entities/content/language"; +import {DwengoContentType} from "../../../../src/services/learning-objects/processing/content-type"; const example: LearningObjectExample = { createLearningObject: () => { @@ -12,6 +13,7 @@ const example: LearningObjectExample = { learningObject.version = 1; learningObject.title = "Multiple choice question for testing"; learningObject.description = "This multiple choice question was only created for testing purposes."; + learningObject.contentType = DwengoContentType.GIFT; learningObject.content = loadTestAsset("learning-objects/test-multiple-choice/content.txt"); return learningObject; }, From a30c4d0d32d6d69a69dcc034d4d93bca97338371 Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Tue, 11 Mar 2025 04:08:32 +0100 Subject: [PATCH 135/180] =?UTF-8?q?feat(backend):=20LearningPathPersonaliz?= =?UTF-8?q?ingService=20ge=C3=AFmplementeerd?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/package.json | 16 +- backend/src/controllers/learning-objects.ts | 2 +- backend/src/exceptions.ts | 1 + .../learning-path-personalizing-service.ts | 66 +++++++- package-lock.json | 160 ++++++------------ 5 files changed, 129 insertions(+), 116 deletions(-) diff --git a/backend/package.json b/backend/package.json index 2d9ea005..1e589752 100644 --- a/backend/package.json +++ b/backend/package.json @@ -18,24 +18,24 @@ "@mikro-orm/postgresql": "^6.4.6", "@mikro-orm/reflection": "^6.4.6", "@mikro-orm/sqlite": "6.4.6", + "@types/cors": "^2.8.17", "@types/js-yaml": "^4.0.9", "axios": "^1.8.2", + "cors": "^2.8.5", "dotenv": "^16.4.7", "express": "^5.0.1", + "express-jwt": "^8.5.1", "gift-pegjs": "^1.0.2", "isomorphic-dompurify": "^2.22.0", - "express-jwt": "^8.5.1", - "jwks-rsa": "^3.1.0", - "uuid": "^11.1.0", "js-yaml": "^4.1.0", - "marked": "^15.0.7", - "uuid": "^11.1.0", + "jsonpath-plus": "^10.3.0", + "jwks-rsa": "^3.1.0", "loki-logger-ts": "^1.0.2", + "marked": "^15.0.7", "response-time": "^2.3.3", + "uuid": "^11.1.0", "winston": "^3.17.0", - "winston-loki": "^6.1.3", - "cors": "^2.8.5", - "@types/cors": "^2.8.17" + "winston-loki": "^6.1.3" }, "devDependencies": { "@mikro-orm/cli": "^6.4.6", diff --git a/backend/src/controllers/learning-objects.ts b/backend/src/controllers/learning-objects.ts index 0445d9f1..ece16057 100644 --- a/backend/src/controllers/learning-objects.ts +++ b/backend/src/controllers/learning-objects.ts @@ -15,7 +15,7 @@ function getLearningObjectIdentifierFromRequest(req: Request): LearningObjectIde return { hruid: req.params.hruid as string, language: (req.query.language || getEnvVar(EnvVars.FallbackLanguage)) as Language, - version: req.query.version as string + version: parseInt(req.query.version as string) }; } diff --git a/backend/src/exceptions.ts b/backend/src/exceptions.ts index 8e2c886c..e93a6c93 100644 --- a/backend/src/exceptions.ts +++ b/backend/src/exceptions.ts @@ -24,6 +24,7 @@ export class UnauthorizedException extends Error { */ export class ForbiddenException extends Error { status = 403; + constructor(message: string = 'Forbidden') { super(message); } diff --git a/backend/src/services/learning-paths/learning-path-personalizing-service.ts b/backend/src/services/learning-paths/learning-path-personalizing-service.ts index 2341cc60..b7d1fe06 100644 --- a/backend/src/services/learning-paths/learning-path-personalizing-service.ts +++ b/backend/src/services/learning-paths/learning-path-personalizing-service.ts @@ -1,5 +1,69 @@ -const learningPathPersonalizingService = { +import {Student} from "../../entities/users/student.entity"; +import {getSubmissionRepository} from "../../data/repositories"; +import {Group} from "../../entities/assignments/group.entity"; +import {Submission} from "../../entities/assignments/submission.entity"; +import {LearningObjectIdentifier} from "../../entities/content/learning-object-identifier"; +import {LearningPathNode} from "../../entities/content/learning-path-node.entity"; +import {LearningPathTransition} from "../../entities/content/learning-path-transition.entity"; +import {JSONPath} from 'jsonpath-plus'; +/** + * Returns the last submission for the learning object associated with the given node and for the student or group + */ +async function getLastRelevantSubmission(node: LearningPathNode, pathFor: {student?: Student, group?: Group}): Promise { + const submissionRepo = getSubmissionRepository(); + const learningObjectId: LearningObjectIdentifier = { + hruid: node.learningObjectHruid, + language: node.language, + version: node.version + }; + let lastSubmission: Submission | null; + if (pathFor.group) { + lastSubmission = await submissionRepo.findMostRecentSubmissionForGroup(learningObjectId, pathFor.group); + } else if (pathFor.student) { + lastSubmission = await submissionRepo.findMostRecentSubmissionForStudent(learningObjectId, pathFor.student); + } else { + throw new Error("The path must either be created for a certain group or for a certain student!"); + } + return lastSubmission; +} + +function transitionPossible(transition: LearningPathTransition, submitted: object | null): boolean { + if (transition.condition === "true" || !transition.condition) { + return true; // If the transition is unconditional, we can go on. + } + if (submitted === null) { + return false; // If the transition is not unconditional and there was no submission, the transition is not possible. + } + return JSONPath({path: transition.condition, json: submitted}).length === 0; +} + +/** + * Service to create individual trajectories from learning paths based on the submissions of the student or group. + */ +const learningPathPersonalizingService = { + async calculatePersonalizedTrajectory(nodes: LearningPathNode[], pathFor: {student?: Student, group?: Group}): Promise { + let trajectory: LearningPathNode[] = []; + + // Always start with the start node. + let currentNode = nodes.filter(it => it.startNode)[0]; + trajectory.push(currentNode); + + while (true) { + // At every node, calculate all the possible next transitions. + let lastSubmission = await getLastRelevantSubmission(currentNode, pathFor); + let submitted = lastSubmission === null ? null : JSON.parse(lastSubmission.content); + let possibleTransitions = currentNode.transitions + .filter(it => transitionPossible(it, submitted)); + + if (possibleTransitions.length === 0) { // If there are none, the trajectory has ended. + return trajectory; + } else { // Otherwise, take the first possible transition. + currentNode = possibleTransitions[0].node; + trajectory.push(currentNode); + } + } + } }; export default learningPathPersonalizingService; diff --git a/package-lock.json b/package-lock.json index 914e100b..c8d5c035 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,17 +36,16 @@ "@types/js-yaml": "^4.0.9", "axios": "^1.8.2", "cors": "^2.8.5", - "@mikro-orm/sqlite": "6.4.6", - "@types/js-yaml": "^4.0.9", "dotenv": "^16.4.7", "express": "^5.0.1", + "express-jwt": "^8.5.1", "gift-pegjs": "^1.0.2", "isomorphic-dompurify": "^2.22.0", - "express-jwt": "^8.5.1", "js-yaml": "^4.1.0", - "marked": "^15.0.7", + "jsonpath-plus": "^10.3.0", "jwks-rsa": "^3.1.0", "loki-logger-ts": "^1.0.2", + "marked": "^15.0.7", "response-time": "^2.3.3", "uuid": "^11.1.0", "winston": "^3.17.0", @@ -155,7 +154,6 @@ }, "node_modules/@asamuzakjp/css-color": { "version": "2.8.3", - "dev": true, "license": "MIT", "dependencies": { "@csstools/css-calc": "^2.1.1", @@ -623,7 +621,6 @@ }, "node_modules/@csstools/color-helpers": { "version": "5.0.1", - "dev": true, "funding": [ { "type": "github", @@ -641,7 +638,6 @@ }, "node_modules/@csstools/css-calc": { "version": "2.1.1", - "dev": true, "funding": [ { "type": "github", @@ -663,7 +659,6 @@ }, "node_modules/@csstools/css-color-parser": { "version": "3.0.7", - "dev": true, "funding": [ { "type": "github", @@ -689,7 +684,6 @@ }, "node_modules/@csstools/css-parser-algorithms": { "version": "3.0.4", - "dev": true, "funding": [ { "type": "github", @@ -710,7 +704,6 @@ }, "node_modules/@csstools/css-tokenizer": { "version": "3.0.3", - "dev": true, "funding": [ { "type": "github", @@ -969,44 +962,6 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@intlify/core-base": { - "version": "10.0.5", - "license": "MIT", - "dependencies": { - "@intlify/message-compiler": "10.0.5", - "@intlify/shared": "10.0.5" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/kazupon" - } - }, - "node_modules/@intlify/message-compiler": { - "version": "10.0.5", - "license": "MIT", - "dependencies": { - "@intlify/shared": "10.0.5", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/kazupon" - } - }, - "node_modules/@intlify/shared": { - "version": "10.0.5", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/kazupon" - } - }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "dev": true, @@ -1084,6 +1039,30 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@jsep-plugin/assignment": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", + "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@jsep-plugin/regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", + "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, "node_modules/@mikro-orm/cli": { "version": "6.4.6", "dev": true, @@ -1721,7 +1700,6 @@ }, "node_modules/@types/http-errors": { "version": "2.0.4", - "dev": true, "license": "MIT" }, "node_modules/@types/js-yaml": { @@ -1755,7 +1733,6 @@ }, "node_modules/@types/mime": { "version": "1.3.5", - "dev": true, "license": "MIT" }, "node_modules/@types/ms": { @@ -1766,7 +1743,6 @@ }, "node_modules/@types/node": { "version": "22.13.4", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.20.0" @@ -1774,12 +1750,10 @@ }, "node_modules/@types/qs": { "version": "6.9.18", - "dev": true, "license": "MIT" }, "node_modules/@types/range-parser": { "version": "1.2.7", - "dev": true, "license": "MIT" }, "node_modules/@types/response-time": { @@ -1795,7 +1769,6 @@ }, "node_modules/@types/send": { "version": "0.17.4", - "dev": true, "license": "MIT", "dependencies": { "@types/mime": "^1", @@ -1804,7 +1777,6 @@ }, "node_modules/@types/serve-static": { "version": "1.15.7", - "dev": true, "license": "MIT", "dependencies": { "@types/http-errors": "*", @@ -2498,7 +2470,6 @@ }, "node_modules/agent-base": { "version": "7.1.3", - "dev": true, "license": "MIT", "engines": { "node": ">= 14" @@ -2636,7 +2607,6 @@ "version": "1.8.2", "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.2.tgz", "integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==", - "version": "1.8.1", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -3135,7 +3105,6 @@ }, "node_modules/color-name": { "version": "1.1.4", - "dev": true, "license": "MIT" }, "node_modules/color-string": { @@ -3315,7 +3284,6 @@ }, "node_modules/cssstyle": { "version": "4.2.1", - "dev": true, "license": "MIT", "dependencies": { "@asamuzakjp/css-color": "^2.8.2", @@ -3331,7 +3299,6 @@ }, "node_modules/data-urls": { "version": "5.0.0", - "dev": true, "license": "MIT", "dependencies": { "whatwg-mimetype": "^4.0.0", @@ -3367,7 +3334,6 @@ }, "node_modules/decimal.js": { "version": "10.5.0", - "dev": true, "license": "MIT" }, "node_modules/decompress-response": { @@ -4804,7 +4770,6 @@ }, "node_modules/html-encoding-sniffer": { "version": "4.0.0", - "dev": true, "license": "MIT", "dependencies": { "whatwg-encoding": "^3.1.1" @@ -4845,7 +4810,6 @@ }, "node_modules/http-proxy-agent": { "version": "7.0.2", - "dev": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.0", @@ -4857,7 +4821,6 @@ }, "node_modules/https-proxy-agent": { "version": "7.0.6", - "dev": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -5097,7 +5060,6 @@ }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", - "dev": true, "license": "MIT" }, "node_modules/is-promise": { @@ -5250,7 +5212,6 @@ }, "node_modules/jsdom": { "version": "26.0.0", - "dev": true, "license": "MIT", "dependencies": { "cssstyle": "^4.2.1", @@ -5289,12 +5250,20 @@ }, "node_modules/jsdom/node_modules/xml-name-validator": { "version": "5.0.0", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18" } }, + "node_modules/jsep": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", + "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + } + }, "node_modules/jsesc": { "version": "3.1.0", "dev": true, @@ -5350,6 +5319,24 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonpath-plus": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.3.0.tgz", + "integrity": "sha512-8TNmfeTCk2Le33A3vRRwtuworG/L5RrgMvdjhKZxvyShO+mBu2fP50OWUjRLNtvw344DdDarFh9buFAZs5ujeA==", + "license": "MIT", + "dependencies": { + "@jsep-plugin/assignment": "^1.3.0", + "@jsep-plugin/regex": "^1.0.4", + "jsep": "^1.4.0" + }, + "bin": { + "jsonpath": "bin/jsonpath-cli.js", + "jsonpath-plus": "bin/jsonpath-cli.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/jsonwebtoken": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", @@ -5663,7 +5650,6 @@ }, "node_modules/lru-cache": { "version": "10.4.3", - "dev": true, "license": "ISC" }, "node_modules/lru-memoizer": { @@ -6399,7 +6385,6 @@ }, "node_modules/nwsapi": { "version": "2.2.16", - "dev": true, "license": "MIT" }, "node_modules/object-assign": { @@ -6579,7 +6564,6 @@ }, "node_modules/parse5": { "version": "7.2.1", - "dev": true, "license": "MIT", "dependencies": { "entities": "^4.5.0" @@ -7049,7 +7033,6 @@ }, "node_modules/punycode": { "version": "2.3.1", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -7354,7 +7337,6 @@ }, "node_modules/rrweb-cssom": { "version": "0.8.0", - "dev": true, "license": "MIT" }, "node_modules/run-applescript": { @@ -7422,7 +7404,6 @@ }, "node_modules/saxes": { "version": "6.0.0", - "dev": true, "license": "ISC", "dependencies": { "xmlchars": "^2.2.0" @@ -8042,7 +8023,6 @@ }, "node_modules/symbol-tree": { "version": "3.2.4", - "dev": true, "license": "MIT" }, "node_modules/synckit": { @@ -8170,7 +8150,6 @@ }, "node_modules/tldts": { "version": "6.1.77", - "dev": true, "license": "MIT", "dependencies": { "tldts-core": "^6.1.77" @@ -8181,7 +8160,6 @@ }, "node_modules/tldts-core": { "version": "6.1.77", - "dev": true, "license": "MIT" }, "node_modules/to-regex-range": { @@ -8211,7 +8189,6 @@ }, "node_modules/tough-cookie": { "version": "5.1.1", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "tldts": "^6.1.32" @@ -8222,7 +8199,6 @@ }, "node_modules/tr46": { "version": "5.0.0", - "dev": true, "license": "MIT", "dependencies": { "punycode": "^2.3.1" @@ -8416,7 +8392,6 @@ }, "node_modules/undici-types": { "version": "6.20.0", - "dev": true, "license": "MIT" }, "node_modules/unicorn-magic": { @@ -8913,24 +8888,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/vue-i18n": { - "version": "10.0.5", - "license": "MIT", - "dependencies": { - "@intlify/core-base": "10.0.5", - "@intlify/shared": "10.0.5", - "@vue/devtools-api": "^6.5.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/kazupon" - }, - "peerDependencies": { - "vue": "^3.0.0" - } - }, "node_modules/vue-router": { "version": "4.5.0", "license": "MIT", @@ -8989,7 +8946,6 @@ }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", - "dev": true, "license": "MIT", "dependencies": { "xml-name-validator": "^5.0.0" @@ -9000,7 +8956,6 @@ }, "node_modules/w3c-xmlserializer/node_modules/xml-name-validator": { "version": "5.0.0", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18" @@ -9008,7 +8963,6 @@ }, "node_modules/webidl-conversions": { "version": "7.0.0", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -9016,7 +8970,6 @@ }, "node_modules/whatwg-encoding": { "version": "3.1.1", - "dev": true, "license": "MIT", "dependencies": { "iconv-lite": "0.6.3" @@ -9027,7 +8980,6 @@ }, "node_modules/whatwg-encoding/node_modules/iconv-lite": { "version": "0.6.3", - "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -9038,7 +8990,6 @@ }, "node_modules/whatwg-mimetype": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -9046,7 +8997,6 @@ }, "node_modules/whatwg-url": { "version": "14.1.1", - "dev": true, "license": "MIT", "dependencies": { "tr46": "^5.0.0", @@ -9289,7 +9239,6 @@ }, "node_modules/ws": { "version": "8.18.0", - "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" @@ -9317,7 +9266,6 @@ }, "node_modules/xmlchars": { "version": "2.2.0", - "dev": true, "license": "MIT" }, "node_modules/xtend": { From aa1a85e64eab8be0ba7c0d7878db8c9e29a08d51 Mon Sep 17 00:00:00 2001 From: Lint Action Date: Tue, 11 Mar 2025 03:09:08 +0000 Subject: [PATCH 136/180] style: fix linting issues met ESLint --- backend/src/controllers/learning-paths.ts | 8 ++--- .../learning-objects/attachment-service.ts | 4 +-- .../dwengo-api-learning-object-provider.ts | 18 +++------- .../learning-object-service.ts | 4 +-- .../processing/extern/extern-processor.ts | 2 +- .../processing/gift/gift-processor.ts | 4 +-- .../multiple-choice-question-renderer.ts | 2 +- .../processing/image/block-image-processor.ts | 2 +- .../markdown/dwengo-marked-renderer.ts | 34 +++++++++---------- .../processing/markdown/markdown-processor.ts | 6 ++-- .../processing/processing-service.ts | 2 +- .../database-learning-path-provider.ts | 4 +-- .../learning-path-personalizing-service.ts | 12 +++---- backend/src/util/async.ts | 2 +- .../content/attachment-repository.test.ts | 6 ++-- .../database-learning-object-provider.test.ts | 4 +-- .../learning-object-service.test.ts | 2 +- .../database-learning-path-provider.test.ts | 6 ++-- .../learning-path-service.test.ts | 8 ++--- ...xample-learning-object-with-attachments.ts | 4 +-- .../pn-werkingnotebooks-example.ts | 12 +++---- .../learning-paths/learning-path-utils.ts | 4 +-- .../learning-paths/pn-werking-example.ts | 2 +- backend/tests/test-utils/expectations.ts | 14 ++++---- 24 files changed, 76 insertions(+), 90 deletions(-) diff --git a/backend/src/controllers/learning-paths.ts b/backend/src/controllers/learning-paths.ts index cb5ae07e..6fadb10d 100644 --- a/backend/src/controllers/learning-paths.ts +++ b/backend/src/controllers/learning-paths.ts @@ -23,9 +23,7 @@ export async function getLearningPaths( ? hruids.map(String) : [String(hruids)]; } else if (themeKey) { - const theme = themes.find((t) => { - return t.title === themeKey; - }); + const theme = themes.find((t) => t.title === themeKey); if (theme) { hruidList = theme.hruids; } else { @@ -39,9 +37,7 @@ export async function getLearningPaths( res.json(searchResults); return; } else { - hruidList = themes.flatMap((theme) => { - return theme.hruids; - }); + hruidList = themes.flatMap((theme) => theme.hruids); } const learningPaths = await learningPathService.fetchLearningPaths( diff --git a/backend/src/services/learning-objects/attachment-service.ts b/backend/src/services/learning-objects/attachment-service.ts index 2285ddfe..fb2b2dd2 100644 --- a/backend/src/services/learning-objects/attachment-service.ts +++ b/backend/src/services/learning-objects/attachment-service.ts @@ -12,9 +12,9 @@ const attachmentService = { language: learningObjectId.language, version: learningObjectId.version, }, attachmentName); - } else { + } return attachmentRepo.findByMostRecentVersionOfLearningObjectAndName(learningObjectId.hruid, learningObjectId.language, attachmentName); - } + } } diff --git a/backend/src/services/learning-objects/dwengo-api-learning-object-provider.ts b/backend/src/services/learning-objects/dwengo-api-learning-object-provider.ts index 628f616c..ab914be4 100644 --- a/backend/src/services/learning-objects/dwengo-api-learning-object-provider.ts +++ b/backend/src/services/learning-objects/dwengo-api-learning-object-provider.ts @@ -68,23 +68,15 @@ async function fetchLearningObjects( const nodes: LearningObjectNode[] = learningPathResponse.data[0].nodes; if (!full) { - return nodes.map((node) => { - return node.learningobject_hruid; - }); + return nodes.map((node) => node.learningobject_hruid); } return await Promise.all( - nodes.map(async (node) => { - return dwengoApiLearningObjectProvider.getLearningObjectById({ + nodes.map(async (node) => dwengoApiLearningObjectProvider.getLearningObjectById({ hruid: node.learningobject_hruid, language: learningPathId.language - }); - }) - ).then((objects) => { - return objects.filter((obj): obj is FilteredLearningObject => { - return obj !== null; - }); - }); + })) + ).then((objects) => objects.filter((obj): obj is FilteredLearningObject => obj !== null)); } catch (error) { console.error('❌ Error fetching learning objects:', error); return []; @@ -98,7 +90,7 @@ const dwengoApiLearningObjectProvider: LearningObjectProvider = { async getLearningObjectById( id: LearningObjectIdentifier ): Promise { - let metadataUrl = `${DWENGO_API_BASE}/learningObject/getMetadata`; + const metadataUrl = `${DWENGO_API_BASE}/learningObject/getMetadata`; const metadata = await fetchWithLogging( metadataUrl, `Metadata for Learning Object HRUID "${id.hruid}" (language ${id.language})`, diff --git a/backend/src/services/learning-objects/learning-object-service.ts b/backend/src/services/learning-objects/learning-object-service.ts index 51152ec8..9dd327f0 100644 --- a/backend/src/services/learning-objects/learning-object-service.ts +++ b/backend/src/services/learning-objects/learning-object-service.ts @@ -11,9 +11,9 @@ import databaseLearningObjectProvider from "./database-learning-object-provider" function getProvider(id: LearningObjectIdentifier): LearningObjectProvider { if (id.hruid.startsWith(getEnvVar(EnvVars.UserContentPrefix))) { return databaseLearningObjectProvider; - } else { + } return dwengoApiLearningObjectProvider; - } + } /** diff --git a/backend/src/services/learning-objects/processing/extern/extern-processor.ts b/backend/src/services/learning-objects/processing/extern/extern-processor.ts index aff26d45..68ec9899 100644 --- a/backend/src/services/learning-objects/processing/extern/extern-processor.ts +++ b/backend/src/services/learning-objects/processing/extern/extern-processor.ts @@ -22,7 +22,7 @@ class ExternProcessor extends StringProcessor { // If a seperate youtube-processor would be added, this code would need to move to that processor // Converts youtube urls to youtube-embed urls - let match = /(.*youtube.com\/)watch\?v=(.*)/.exec(externURL) + const match = /(.*youtube.com\/)watch\?v=(.*)/.exec(externURL) if (match) { externURL = match[1] + "embed/" + match[2]; } diff --git a/backend/src/services/learning-objects/processing/gift/gift-processor.ts b/backend/src/services/learning-objects/processing/gift/gift-processor.ts index 5d20e99c..b6eba8ba 100644 --- a/backend/src/services/learning-objects/processing/gift/gift-processor.ts +++ b/backend/src/services/learning-objects/processing/gift/gift-processor.ts @@ -38,9 +38,9 @@ class GiftProcessor extends StringProcessor { let html = "
\n"; let i = 1; - for (let question of quizQuestions) { + for (const question of quizQuestions) { html += `
\n`; - html += " " + this.renderQuestion(question, i).replaceAll(/\n(.+)/g, "\n $1"); // replace for indentation. + html += " " + this.renderQuestion(question, i).replaceAll(/\n(.+)/g, "\n $1"); // Replace for indentation. html += `
\n`; i++; } diff --git a/backend/src/services/learning-objects/processing/gift/question-renderers/multiple-choice-question-renderer.ts b/backend/src/services/learning-objects/processing/gift/question-renderers/multiple-choice-question-renderer.ts index 6b6d8eea..bf1de8c4 100644 --- a/backend/src/services/learning-objects/processing/gift/question-renderers/multiple-choice-question-renderer.ts +++ b/backend/src/services/learning-objects/processing/gift/question-renderers/multiple-choice-question-renderer.ts @@ -11,7 +11,7 @@ export class MultipleChoiceQuestionRenderer extends GIFTQuestionRenderer${question.stem.text}

\n`; } let i = 0; - for (let choice of question.choices) { + for (const choice of question.choices) { renderedHtml += `
\n`; renderedHtml += ` \n`; renderedHtml += ` \n`; diff --git a/backend/src/services/learning-objects/processing/image/block-image-processor.ts b/backend/src/services/learning-objects/processing/image/block-image-processor.ts index cb488e92..7d578e1c 100644 --- a/backend/src/services/learning-objects/processing/image/block-image-processor.ts +++ b/backend/src/services/learning-objects/processing/image/block-image-processor.ts @@ -11,7 +11,7 @@ class BlockImageProcessor extends InlineImageProcessor { } override renderFn(imageUrl: string){ - let inlineHtml = super.render(imageUrl); + const inlineHtml = super.render(imageUrl); return DOMPurify.sanitize(`
${inlineHtml}
`); } } diff --git a/backend/src/services/learning-objects/processing/markdown/dwengo-marked-renderer.ts b/backend/src/services/learning-objects/processing/markdown/dwengo-marked-renderer.ts index 04b15b94..d5324754 100644 --- a/backend/src/services/learning-objects/processing/markdown/dwengo-marked-renderer.ts +++ b/backend/src/services/learning-objects/processing/markdown/dwengo-marked-renderer.ts @@ -56,53 +56,53 @@ function extractLearningObjectIdFromHref(href: string): LearningObjectIdentifier }, // When the syntax for a link is used => [text](href "title") - // render a custom link when the prefix for a learning object is used. + // Render a custom link when the prefix for a learning object is used. link(link: Link): string { const href = link.href; const title = link.title || ""; const text = marked.parseInline(link.text); // There could for example be an image in the link. if (href.startsWith(prefixes.learningObject)) { - // link to learning-object + // Link to learning-object const learningObjectId = extractLearningObjectIdFromHref(href); return `${text}`; - } else { - // any other link + } + // Any other link if (!isValidHttpUrl(href)) { throw new ProcessingError("Link is not a valid HTTP URL!"); } // return `${text}`; - } + }, // When the syntax for an image is used => ![text](href "title") - // render a learning object, pdf, audio or video if a prefix is used. + // Render a learning object, pdf, audio or video if a prefix is used. image(img: Image): string { const href = img.href; if (href.startsWith(prefixes.learningObject)) { - // embedded learning-object + // Embedded learning-object const learningObjectId = extractLearningObjectIdFromHref(href); return ` `; // Placeholder for the learning object since we cannot fetch its HTML here (this has to be a sync function!) } else if (href.startsWith(prefixes.pdf)) { - // embedded pdf - let proc = new PdfProcessor(); + // Embedded pdf + const proc = new PdfProcessor(); return proc.render(href.split(/\/(.+)/, 2)[1]); } else if (href.startsWith(prefixes.audio)) { - // embedded audio - let proc = new AudioProcessor(); + // Embedded audio + const proc = new AudioProcessor(); return proc.render(href.split(/\/(.+)/, 2)[1]); } else if (href.startsWith(prefixes.extern) || href.startsWith(prefixes.video) || href.startsWith(prefixes.notebook)) { - // embedded youtube video or notebook (or other extern content) - let proc = new ExternProcessor(); + // Embedded youtube video or notebook (or other extern content) + const proc = new ExternProcessor(); return proc.render(href.split(/\/(.+)/, 2)[1]); - } else { - // embedded image - let proc = new InlineImageProcessor(); + } + // Embedded image + const proc = new InlineImageProcessor(); return proc.render(href) - } + }, } diff --git a/backend/src/services/learning-objects/processing/markdown/markdown-processor.ts b/backend/src/services/learning-objects/processing/markdown/markdown-processor.ts index c20f08a3..58824c13 100644 --- a/backend/src/services/learning-objects/processing/markdown/markdown-processor.ts +++ b/backend/src/services/learning-objects/processing/markdown/markdown-processor.ts @@ -27,7 +27,7 @@ class MarkdownProcessor extends StringProcessor { } replaceLinks(html: string) { - let proc = new InlineImageProcessor(); + const proc = new InlineImageProcessor(); html = html.replace(//g, ( match: string, src: string, @@ -35,9 +35,7 @@ class MarkdownProcessor extends StringProcessor { altText: string, title: string, titleText: string - ) => { - return proc.render(src); - }); + ) => proc.render(src)); return html; } } diff --git a/backend/src/services/learning-objects/processing/processing-service.ts b/backend/src/services/learning-objects/processing/processing-service.ts index a9885718..c682de32 100644 --- a/backend/src/services/learning-objects/processing/processing-service.ts +++ b/backend/src/services/learning-objects/processing/processing-service.ts @@ -54,7 +54,7 @@ class ProcessingService { learningObject: LearningObject, fetchEmbeddedLearningObjects?: (loId: LearningObjectIdentifier) => Promise ): Promise { - let html = this.processors.get(learningObject.contentType)!.renderLearningObject(learningObject); + const html = this.processors.get(learningObject.contentType)!.renderLearningObject(learningObject); if (fetchEmbeddedLearningObjects) { // Replace all embedded learning objects. return replaceAsync( diff --git a/backend/src/services/learning-paths/database-learning-path-provider.ts b/backend/src/services/learning-paths/database-learning-path-provider.ts index b9fa9ff6..60edb98b 100644 --- a/backend/src/services/learning-paths/database-learning-path-provider.ts +++ b/backend/src/services/learning-paths/database-learning-path-provider.ts @@ -22,7 +22,7 @@ import {LearningPathTransition} from "../../entities/content/learning-path-trans */ async function getLearningObjectsForNodes(nodes: LearningPathNode[]): Promise> { // Fetching the corresponding learning object for each of the nodes and creating a map that maps each node to - // its corresponding learning object. + // Its corresponding learning object. const nullableNodesToLearningObjects = new Map( await Promise.all( nodes.map(node => @@ -58,7 +58,7 @@ async function convertLearningPath(learningPath: LearningPathEntity, order: numb const image = learningPath.image ? learningPath.image.toString("base64") : undefined; return { - _id: `${learningPath.hruid}/${learningPath.language}`, // for backwards compatibility with the original Dwengo API. + _id: `${learningPath.hruid}/${learningPath.language}`, // For backwards compatibility with the original Dwengo API. __order: order, hruid: learningPath.hruid, language: learningPath.language, diff --git a/backend/src/services/learning-paths/learning-path-personalizing-service.ts b/backend/src/services/learning-paths/learning-path-personalizing-service.ts index b7d1fe06..6cd8f610 100644 --- a/backend/src/services/learning-paths/learning-path-personalizing-service.ts +++ b/backend/src/services/learning-paths/learning-path-personalizing-service.ts @@ -43,7 +43,7 @@ function transitionPossible(transition: LearningPathTransition, submitted: objec */ const learningPathPersonalizingService = { async calculatePersonalizedTrajectory(nodes: LearningPathNode[], pathFor: {student?: Student, group?: Group}): Promise { - let trajectory: LearningPathNode[] = []; + const trajectory: LearningPathNode[] = []; // Always start with the start node. let currentNode = nodes.filter(it => it.startNode)[0]; @@ -51,17 +51,17 @@ const learningPathPersonalizingService = { while (true) { // At every node, calculate all the possible next transitions. - let lastSubmission = await getLastRelevantSubmission(currentNode, pathFor); - let submitted = lastSubmission === null ? null : JSON.parse(lastSubmission.content); - let possibleTransitions = currentNode.transitions + const lastSubmission = await getLastRelevantSubmission(currentNode, pathFor); + const submitted = lastSubmission === null ? null : JSON.parse(lastSubmission.content); + const possibleTransitions = currentNode.transitions .filter(it => transitionPossible(it, submitted)); if (possibleTransitions.length === 0) { // If there are none, the trajectory has ended. return trajectory; - } else { // Otherwise, take the first possible transition. + } // Otherwise, take the first possible transition. currentNode = possibleTransitions[0].node; trajectory.push(currentNode); - } + } } }; diff --git a/backend/src/util/async.ts b/backend/src/util/async.ts index f37f53a0..874c0b8e 100644 --- a/backend/src/util/async.ts +++ b/backend/src/util/async.ts @@ -19,5 +19,5 @@ export async function replaceAsync(str: string, regex: RegExp, replacementFn: (m const replacements: string[] = (await Promise.all(promises)); // Second run through matches: Replace them by their previously computed replacements. - return str.replace(regex, () => replacements.pop()!!); + return str.replace(regex, () => replacements.pop()!); } diff --git a/backend/tests/data/content/attachment-repository.test.ts b/backend/tests/data/content/attachment-repository.test.ts index 3f573cdb..e6c4e44a 100644 --- a/backend/tests/data/content/attachment-repository.test.ts +++ b/backend/tests/data/content/attachment-repository.test.ts @@ -11,10 +11,10 @@ import {LearningObjectIdentifier} from "../../../src/entities/content/learning-o const NEWER_TEST_SUFFIX = "nEweR"; function createTestLearningObjects(learningObjectRepo: LearningObjectRepository): {older: LearningObject, newer: LearningObject} { - let olderExample = example.createLearningObject(); + const olderExample = example.createLearningObject(); learningObjectRepo.save(olderExample); - let newerExample = example.createLearningObject(); + const newerExample = example.createLearningObject(); newerExample.title = "Newer example"; newerExample.version = 100; @@ -40,7 +40,7 @@ describe("AttachmentRepository", () => { .values(example.createAttachment) .map(fn => fn(exampleLearningObjects.older)); - for (let attachment of attachmentsOlderLearningObject) { + for (const attachment of attachmentsOlderLearningObject) { attachmentRepo.save(attachment); } }); diff --git a/backend/tests/services/learning-objects/database-learning-object-provider.test.ts b/backend/tests/services/learning-objects/database-learning-object-provider.test.ts index 691b29ba..e3960f64 100644 --- a/backend/tests/services/learning-objects/database-learning-object-provider.test.ts +++ b/backend/tests/services/learning-objects/database-learning-object-provider.test.ts @@ -12,8 +12,8 @@ import {FilteredLearningObject} from "../../../src/interfaces/learning-content"; import {Language} from "../../../src/entities/content/language"; async function initExampleData(): Promise { - let learningObjectRepo = getLearningObjectRepository(); - let exampleLearningObject = createExampleLearningObjectWithAttachments(example); + const learningObjectRepo = getLearningObjectRepository(); + const exampleLearningObject = createExampleLearningObjectWithAttachments(example); await learningObjectRepo.insert(exampleLearningObject); return exampleLearningObject; } diff --git a/backend/tests/services/learning-objects/learning-object-service.test.ts b/backend/tests/services/learning-objects/learning-object-service.test.ts index 970e4675..2a68d797 100644 --- a/backend/tests/services/learning-objects/learning-object-service.test.ts +++ b/backend/tests/services/learning-objects/learning-object-service.test.ts @@ -18,7 +18,7 @@ const DWENGO_TEST_LEARNING_OBJECT_ID: LearningObjectIdentifier = { async function initExampleData(): Promise { const learningObjectRepo = getLearningObjectRepository(); - let learningObject = learningObjectExample.createLearningObject(); + const learningObject = learningObjectExample.createLearningObject(); learningObject.title = TEST_LEARNING_OBJECT_TITLE await learningObjectRepo.save(learningObject); return learningObject; diff --git a/backend/tests/services/learning-path/database-learning-path-provider.test.ts b/backend/tests/services/learning-path/database-learning-path-provider.test.ts index 0d46c1e0..8dd3d07b 100644 --- a/backend/tests/services/learning-path/database-learning-path-provider.test.ts +++ b/backend/tests/services/learning-path/database-learning-path-provider.test.ts @@ -14,8 +14,8 @@ import {Language} from "../../../src/entities/content/language"; async function initExampleData(): Promise<{ learningObject: LearningObject, learningPath: LearningPath }> { const learningObjectRepo = getLearningObjectRepository(); const learningPathRepo = getLearningPathRepository(); - let learningObject = learningObjectExample.createLearningObject(); - let learningPath = learningPathExample.createLearningPath(); + const learningObject = learningObjectExample.createLearningObject(); + const learningPath = learningPathExample.createLearningPath(); await learningObjectRepo.save(learningObject); await learningPathRepo.save(learningPath); return { learningObject, learningPath }; @@ -55,7 +55,7 @@ describe("DatabaseLearningPathProvider", () => { it("returns a non-successful response if a non-existing learning path is queried", async () => { const result = await databaseLearningPathProvider.fetchLearningPaths( [example.learningPath.hruid], - Language.Abkhazian, // wrong language + Language.Abkhazian, // Wrong language "the source" ); diff --git a/backend/tests/services/learning-path/learning-path-service.test.ts b/backend/tests/services/learning-path/learning-path-service.test.ts index 83db1bef..b64d527a 100644 --- a/backend/tests/services/learning-path/learning-path-service.test.ts +++ b/backend/tests/services/learning-path/learning-path-service.test.ts @@ -11,8 +11,8 @@ import learningPathService from "../../../src/services/learning-paths/learning-p async function initExampleData(): Promise<{ learningObject: LearningObject, learningPath: LearningPath }> { const learningObjectRepo = getLearningObjectRepository(); const learningPathRepo = getLearningPathRepository(); - let learningObject = learningObjectExample.createLearningObject(); - let learningPath = learningPathExample.createLearningPath(); + const learningObject = learningObjectExample.createLearningObject(); + const learningPath = learningPathExample.createLearningPath(); await learningObjectRepo.save(learningObject); await learningPathRepo.save(learningPath); return { learningObject, learningPath }; @@ -76,7 +76,7 @@ describe("LearningPathService", () => { ).length ).toBe(1); - // but should not only find that one. + // But should not only find that one. expect(result.length).not.toBeLessThan(2); }); it("should still return results from the Dwengo API even though there are no matches in the database", async () => { @@ -88,7 +88,7 @@ describe("LearningPathService", () => { // Should find something... expect(result.length).not.toBe(0); - // but not the example learning path. + // But not the example learning path. expect( result.filter(it => it.hruid === example.learningPath.hruid && it.title === example.learningPath.title diff --git a/backend/tests/test-assets/learning-objects/create-example-learning-object-with-attachments.ts b/backend/tests/test-assets/learning-objects/create-example-learning-object-with-attachments.ts index 65d2b62e..c0177fbf 100644 --- a/backend/tests/test-assets/learning-objects/create-example-learning-object-with-attachments.ts +++ b/backend/tests/test-assets/learning-objects/create-example-learning-object-with-attachments.ts @@ -2,8 +2,8 @@ import {LearningObjectExample} from "./learning-object-example"; import {LearningObject} from "../../../src/entities/content/learning-object.entity"; export function createExampleLearningObjectWithAttachments(example: LearningObjectExample): LearningObject { - let learningObject = example.createLearningObject(); - for (let creationFn of Object.values(example.createAttachment)) { + const learningObject = example.createLearningObject(); + for (const creationFn of Object.values(example.createAttachment)) { learningObject.attachments.push(creationFn(learningObject)); } return learningObject; diff --git a/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.ts b/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.ts index 09cab0f9..9a7f340c 100644 --- a/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.ts +++ b/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.ts @@ -10,7 +10,7 @@ const ASSETS_PREFIX = "learning-objects/pn-werkingnotebooks/"; const example: LearningObjectExample = { createLearningObject: ()=> { - let learningObject = new LearningObject(); + const learningObject = new LearningObject(); learningObject.hruid = `${getEnvVar(EnvVars.UserContentPrefix)}pn_werkingnotebooks`; learningObject.version = 3; learningObject.language = Language.Dutch; @@ -18,11 +18,11 @@ const example: LearningObjectExample = { learningObject.description = "Leren werken met notebooks"; learningObject.keywords = ["Python", "KIKS", "Wiskunde", "STEM", "AI"] - let educationalGoal1 = new EducationalGoal(); + const educationalGoal1 = new EducationalGoal(); educationalGoal1.source = "Source"; educationalGoal1.id = "id"; - let educationalGoal2 = new EducationalGoal(); + const educationalGoal2 = new EducationalGoal(); educationalGoal2.source = "Source2"; educationalGoal2.id = "id2"; @@ -39,7 +39,7 @@ const example: LearningObjectExample = { learningObject.license = "dwengo"; learningObject.estimatedTime = 10; - let returnValue = new ReturnValue(); + const returnValue = new ReturnValue(); returnValue.callbackUrl = "callback_url_example"; returnValue.callbackSchema = '{"att": "test", "att2": "test2"}'; @@ -51,7 +51,7 @@ const example: LearningObjectExample = { }, createAttachment: { dwengoLogo: (learningObject) => { - let att = new Attachment(); + const att = new Attachment(); att.learningObject = learningObject; att.name = "dwengo.png"; att.mimeType = "image/png"; @@ -59,7 +59,7 @@ const example: LearningObjectExample = { return att; }, knop: (learningObject) => { - let att = new Attachment(); + const att = new Attachment(); att.learningObject = learningObject; att.name = "Knop.png"; att.mimeType = "image/png"; diff --git a/backend/tests/test-assets/learning-paths/learning-path-utils.ts b/backend/tests/test-assets/learning-paths/learning-path-utils.ts index 68c49412..0a09145f 100644 --- a/backend/tests/test-assets/learning-paths/learning-path-utils.ts +++ b/backend/tests/test-assets/learning-paths/learning-path-utils.ts @@ -4,7 +4,7 @@ import {LearningPathNode} from "../../../src/entities/content/learning-path-node import {LearningPath} from "../../../src/entities/content/learning-path.entity"; export function createLearningPathTransition(node: LearningPathNode, transitionNumber: number, condition: string | null, to: LearningPathNode) { - let trans = new LearningPathTransition(); + const trans = new LearningPathTransition(); trans.node = node; trans.transitionNumber = transitionNumber; trans.condition = condition || "true"; @@ -20,7 +20,7 @@ export function createLearningPathNode( language: Language, startNode: boolean ) { - let node = new LearningPathNode(); + const node = new LearningPathNode(); node.learningPath = learningPath; node.nodeNumber = nodeNumber; node.learningObjectHruid = learningObjectHruid; diff --git a/backend/tests/test-assets/learning-paths/pn-werking-example.ts b/backend/tests/test-assets/learning-paths/pn-werking-example.ts index a96de552..40a07587 100644 --- a/backend/tests/test-assets/learning-paths/pn-werking-example.ts +++ b/backend/tests/test-assets/learning-paths/pn-werking-example.ts @@ -5,7 +5,7 @@ import {createLearningPathNode, createLearningPathTransition} from "./learning-p import {LearningPathNode} from "../../../src/entities/content/learning-path-node.entity"; function createNodes(learningPath: LearningPath): LearningPathNode[] { - let nodes = [ + const nodes = [ createLearningPathNode(learningPath, 0, "u_pn_werkingnotebooks", 3, Language.Dutch, true), createLearningPathNode(learningPath, 1, "pn_werkingnotebooks2", 3, Language.Dutch, false), createLearningPathNode(learningPath, 2, "pn_werkingnotebooks3", 3, Language.Dutch, false), diff --git a/backend/tests/test-utils/expectations.ts b/backend/tests/test-utils/expectations.ts index 19c2408d..b7e9523b 100644 --- a/backend/tests/test-utils/expectations.ts +++ b/backend/tests/test-utils/expectations.ts @@ -22,7 +22,7 @@ export function expectToBeCorrectEntity( if (!expected.name) { expected.name = "expected"; } - for (let property in expected.entity) { + for (const property in expected.entity) { if ( property !in IGNORE_PROPERTIES && expected.entity[property] !== undefined // If we don't expect a certain value for a property, we assume it can be filled in by the database however it wants. @@ -34,10 +34,10 @@ export function expectToBeCorrectEntity( }); } if (typeof expected.entity[property] === "boolean") { // Sometimes, booleans get represented by numbers 0 and 1 in the objects actual from the database. - if (!!expected.entity[property] !== !!actual.entity[property]) { + if (Boolean(expected.entity[property]) !== Boolean(actual.entity[property])) { throw new AssertionError({ message: `${property} was ${expected.entity[property]} in ${expected.name}, - but ${actual.entity[property]} (${!!expected.entity[property]}) in ${actual.name}` + but ${actual.entity[property]} (${Boolean(expected.entity[property])}) in ${actual.name}` }); } } else if (typeof expected.entity[property] !== typeof actual.entity[property]) { @@ -78,7 +78,7 @@ export function expectToBeCorrectFilteredLearningObject(filtered: FilteredLearni expect(filtered.key).toEqual(original.hruid); expect(filtered.targetAges).toEqual(original.targetAges); expect(filtered.title).toEqual(original.title); - expect(!!filtered.teacherExclusive).toEqual(original.teacherExclusive) // !!: Workaround: MikroORM with SQLite returns 0 and 1 instead of booleans. + expect(Boolean(filtered.teacherExclusive)).toEqual(original.teacherExclusive) // !!: Workaround: MikroORM with SQLite returns 0 and 1 instead of booleans. expect(filtered.skosConcepts).toEqual(original.skosConcepts); expect(filtered.estimatedTime).toEqual(original.estimatedTime); expect(filtered.educationalGoals).toEqual(original.educationalGoals); @@ -123,21 +123,21 @@ export function expectToBeCorrectLearningPath( expect(learningPath.num_nodes).toEqual(expectedEntity.nodes.length); expect(learningPath.image || null).toEqual(expectedEntity.image); - let expectedLearningPathNodes = new Map( + const expectedLearningPathNodes = new Map( expectedEntity.nodes.map(node => [ {learningObjectHruid: node.learningObjectHruid, language: node.language, version: node.version}, {startNode: node.startNode, transitions: node.transitions} ]) ); - for (let node of learningPath.nodes) { + for (const node of learningPath.nodes) { const nodeKey = { learningObjectHruid: node.learningobject_hruid, language: node.language, version: node.version }; expect(expectedLearningPathNodes.keys()).toContainEqual(nodeKey); - let expectedNode = [...expectedLearningPathNodes.entries()] + const expectedNode = [...expectedLearningPathNodes.entries()] .filter(([key, _]) => key.learningObjectHruid === nodeKey.learningObjectHruid && key.language === node.language From 2a2881ec30f84f4f3f75eda14849a133e02b7de9 Mon Sep 17 00:00:00 2001 From: Lint Action Date: Tue, 11 Mar 2025 03:09:12 +0000 Subject: [PATCH 137/180] style: fix linting issues met Prettier --- backend/src/config.ts | 2 +- backend/src/controllers/learning-objects.ts | 36 ++--- backend/src/controllers/learning-paths.ts | 24 +--- backend/src/controllers/learningPaths.ts | 1 - .../src/data/content/attachment-repository.ts | 40 +++--- .../content/learning-object-repository.ts | 16 +-- .../data/content/learning-path-repository.ts | 23 +--- backend/src/data/repositories.ts | 19 +-- .../entities/assignments/assignment.entity.ts | 4 +- .../src/entities/assignments/group.entity.ts | 4 +- .../entities/assignments/submission.entity.ts | 4 +- .../classes/class-join-request.entity.ts | 4 +- backend/src/entities/classes/class.entity.ts | 4 +- .../classes/teacher-invitation.entity.ts | 4 +- .../src/entities/content/attachment.entity.ts | 4 +- backend/src/entities/content/language.ts | 2 +- .../content/learning-object.entity.ts | 10 +- .../content/learning-path-node.entity.ts | 13 +- .../learning-path-transition.entity.ts | 6 +- .../entities/content/learning-path.entity.ts | 16 +-- .../src/entities/questions/answer.entity.ts | 4 +- .../src/entities/questions/question.entity.ts | 4 +- backend/src/entities/users/teacher.entity.ts | 4 +- backend/src/interfaces/learning-content.ts | 2 +- backend/src/routes/learning-objects.ts | 5 +- .../learning-objects/attachment-service.ts | 28 ++-- .../database-learning-object-provider.ts | 58 ++++---- .../dwengo-api-learning-object-provider.ts | 70 ++++------ .../learning-object-provider.ts | 6 +- .../learning-object-service.ts | 21 ++- .../processing/audio/audio-processor.ts | 7 +- .../processing/content-type.ts | 22 +-- .../processing/extern/extern-processor.ts | 20 +-- .../processing/gift/gift-processor.ts | 35 +++-- .../category-question-renderer.ts | 6 +- .../description-question-renderer.ts | 6 +- .../essay-question-renderer.ts | 6 +- .../gift-question-renderer.ts | 2 +- .../matching-question-renderer.ts | 6 +- .../multiple-choice-question-renderer.ts | 6 +- .../numerical-question-renderer.ts | 6 +- .../short-question-renderer.ts | 6 +- .../true-false-question-renderer.ts | 6 +- .../processing/image/block-image-processor.ts | 6 +- .../image/inline-image-processor.ts | 8 +- .../markdown/dwengo-marked-renderer.ts | 66 ++++----- .../processing/markdown/markdown-processor.ts | 28 ++-- .../processing/pdf/pdf-processor.ts | 14 +- .../processing/processing-service.ts | 36 +++-- .../learning-objects/processing/processor.ts | 6 +- .../processing/string-processor.ts | 6 +- .../processing/text/text-processor.ts | 4 +- .../database-learning-path-provider.ts | 128 ++++++++---------- .../dwengo-api-learning-path-provider.ts | 32 +---- .../learning-path-personalizing-service.ts | 45 +++--- .../learning-paths/learning-path-provider.ts | 4 +- .../learning-paths/learning-path-service.ts | 37 ++--- backend/src/util/apiHelper.ts | 6 +- backend/src/util/async.ts | 2 +- backend/src/util/envvars.ts | 6 +- backend/src/util/links.ts | 6 +- .../content/attachment-repository.test.ts | 54 ++++---- .../learning-object-repository.test.ts | 56 ++++---- .../content/learning-path-repository.test.ts | 58 ++++---- .../database-learning-object-provider.test.ts | 42 +++--- .../learning-object-service.test.ts | 75 +++++----- .../processing/processing-service.test.ts | 18 +-- .../database-learning-path-provider.test.ts | 71 +++++----- .../learning-path-service.test.ts | 97 +++++-------- ...xample-learning-object-with-attachments.ts | 4 +- .../dummy/dummy-learning-object-example.ts | 18 +-- .../learning-object-example.d.ts | 10 +- .../pn-werkingnotebooks/content.md | 9 +- .../pn-werkingnotebooks-example.ts | 60 ++++---- .../pn-werkingnotebooks/rendering.html | 51 +++++-- .../test-essay/test-essay-example.ts | 20 +-- .../test-multiple-choice/rendering.html | 4 +- .../test-multiple-choice-example.ts | 20 +-- .../learning-paths/learning-path-example.d.ts | 2 +- .../learning-paths/learning-path-utils.ts | 10 +- .../learning-paths/pn-werking-example.ts | 28 ++-- .../learning-paths/test-conditions-example.ts | 42 +++--- backend/tests/test-utils/expectations.ts | 94 ++++++------- backend/tests/test-utils/load-test-asset.ts | 4 +- 84 files changed, 846 insertions(+), 1013 deletions(-) diff --git a/backend/src/config.ts b/backend/src/config.ts index 848eb07e..df8fa133 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -1,4 +1,4 @@ -import {EnvVars, getEnvVar} from "./util/envvars"; +import { EnvVars, getEnvVar } from './util/envvars'; // API export const DWENGO_API_BASE = getEnvVar(EnvVars.LearningContentRepoApiBaseUrl); diff --git a/backend/src/controllers/learning-objects.ts b/backend/src/controllers/learning-objects.ts index ece16057..cb4862e9 100644 --- a/backend/src/controllers/learning-objects.ts +++ b/backend/src/controllers/learning-objects.ts @@ -1,38 +1,35 @@ import { Request, Response } from 'express'; import { FALLBACK_LANG } from '../config.js'; -import {FilteredLearningObject, LearningObjectIdentifier, LearningPathIdentifier} from '../interfaces/learning-content'; -import learningObjectService from "../services/learning-objects/learning-object-service"; -import {EnvVars, getEnvVar} from "../util/envvars"; -import {Language} from "../entities/content/language"; -import {BadRequestException} from "../exceptions"; -import attachmentService from "../services/learning-objects/attachment-service"; -import {NotFoundError} from "@mikro-orm/core"; +import { FilteredLearningObject, LearningObjectIdentifier, LearningPathIdentifier } from '../interfaces/learning-content'; +import learningObjectService from '../services/learning-objects/learning-object-service'; +import { EnvVars, getEnvVar } from '../util/envvars'; +import { Language } from '../entities/content/language'; +import { BadRequestException } from '../exceptions'; +import attachmentService from '../services/learning-objects/attachment-service'; +import { NotFoundError } from '@mikro-orm/core'; function getLearningObjectIdentifierFromRequest(req: Request): LearningObjectIdentifier { if (!req.params.hruid) { - throw new BadRequestException("HRUID is required."); + throw new BadRequestException('HRUID is required.'); } return { hruid: req.params.hruid as string, language: (req.query.language || getEnvVar(EnvVars.FallbackLanguage)) as Language, - version: parseInt(req.query.version as string) + version: parseInt(req.query.version as string), }; } function getLearningPathIdentifierFromRequest(req: Request): LearningPathIdentifier { if (!req.query.hruid) { - throw new BadRequestException("HRUID is required."); + throw new BadRequestException('HRUID is required.'); } return { hruid: req.params.hruid as string, - language: (req.query.language as Language) || FALLBACK_LANG - } + language: (req.query.language as Language) || FALLBACK_LANG, + }; } -export async function getAllLearningObjects( - req: Request, - res: Response -): Promise { +export async function getAllLearningObjects(req: Request, res: Response): Promise { const learningPathId = getLearningPathIdentifierFromRequest(req); const full = req.query.full; @@ -46,10 +43,7 @@ export async function getAllLearningObjects( res.json(learningObjects); } -export async function getLearningObject( - req: Request, - res: Response -): Promise { +export async function getLearningObject(req: Request, res: Response): Promise { const learningObjectId = getLearningObjectIdentifierFromRequest(req); const learningObject = await learningObjectService.getLearningObjectById(learningObjectId); @@ -71,5 +65,5 @@ export async function getAttachment(req: Request, res: Response): Promise if (!attachment) { throw new NotFoundError(`Attachment ${name} not found`); } - res.setHeader("Content-Type", attachment.mimeType).send(attachment.content) + res.setHeader('Content-Type', attachment.mimeType).send(attachment.content); } diff --git a/backend/src/controllers/learning-paths.ts b/backend/src/controllers/learning-paths.ts index 6fadb10d..8e654d02 100644 --- a/backend/src/controllers/learning-paths.ts +++ b/backend/src/controllers/learning-paths.ts @@ -1,16 +1,13 @@ import { Request, Response } from 'express'; import { themes } from '../data/themes.js'; import { FALLBACK_LANG } from '../config.js'; -import learningPathService from "../services/learning-paths/learning-path-service"; -import {NotFoundException} from "../exceptions"; +import learningPathService from '../services/learning-paths/learning-path-service'; +import { NotFoundException } from '../exceptions'; /** * Fetch learning paths based on query parameters. */ -export async function getLearningPaths( - req: Request, - res: Response -): Promise { +export async function getLearningPaths(req: Request, res: Response): Promise { const hruids = req.query.hruid; const themeKey = req.query.theme as string; const searchQuery = req.query.search as string; @@ -19,9 +16,7 @@ export async function getLearningPaths( let hruidList; if (hruids) { - hruidList = Array.isArray(hruids) - ? hruids.map(String) - : [String(hruids)]; + hruidList = Array.isArray(hruids) ? hruids.map(String) : [String(hruids)]; } else if (themeKey) { const theme = themes.find((t) => t.title === themeKey); if (theme) { @@ -30,20 +25,13 @@ export async function getLearningPaths( throw new NotFoundException(`Theme "${themeKey}" not found.`); } } else if (searchQuery) { - const searchResults = await learningPathService.searchLearningPaths( - searchQuery, - language - ); + const searchResults = await learningPathService.searchLearningPaths(searchQuery, language); res.json(searchResults); return; } else { hruidList = themes.flatMap((theme) => theme.hruids); } - const learningPaths = await learningPathService.fetchLearningPaths( - hruidList, - language, - `HRUIDs: ${hruidList.join(', ')}` - ); + const learningPaths = await learningPathService.fetchLearningPaths(hruidList, language, `HRUIDs: ${hruidList.join(', ')}`); res.json(learningPaths.data); } diff --git a/backend/src/controllers/learningPaths.ts b/backend/src/controllers/learningPaths.ts index 707334b7..50299d0f 100644 --- a/backend/src/controllers/learningPaths.ts +++ b/backend/src/controllers/learningPaths.ts @@ -1,4 +1,3 @@ - import { Request, Response } from 'express'; import { themes } from '../data/themes.js'; import { FALLBACK_LANG } from '../config.js'; diff --git a/backend/src/data/content/attachment-repository.ts b/backend/src/data/content/attachment-repository.ts index c7a53c86..95c5ab1c 100644 --- a/backend/src/data/content/attachment-repository.ts +++ b/backend/src/data/content/attachment-repository.ts @@ -1,13 +1,10 @@ import { DwengoEntityRepository } from '../dwengo-entity-repository.js'; import { Attachment } from '../../entities/content/attachment.entity.js'; -import {Language} from "../../entities/content/language"; -import {LearningObjectIdentifier} from "../../entities/content/learning-object-identifier"; +import { Language } from '../../entities/content/language'; +import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier'; export class AttachmentRepository extends DwengoEntityRepository { - public findByLearningObjectIdAndName( - learningObjectId: LearningObjectIdentifier, - name: string - ): Promise { + public findByLearningObjectIdAndName(learningObjectId: LearningObjectIdentifier, name: string): Promise { return this.findOne({ learningObject: { hruid: learningObjectId.hruid, @@ -18,24 +15,23 @@ export class AttachmentRepository extends DwengoEntityRepository { }); } - public findByMostRecentVersionOfLearningObjectAndName( - hruid: string, - language: Language, - attachmentName: string - ): Promise { - return this.findOne({ - learningObject: { - hruid: hruid, - language: language - }, - name: attachmentName - }, { - orderBy: { + public findByMostRecentVersionOfLearningObjectAndName(hruid: string, language: Language, attachmentName: string): Promise { + return this.findOne( + { learningObject: { - version: 'DESC' - } + hruid: hruid, + language: language, + }, + name: attachmentName, + }, + { + orderBy: { + learningObject: { + version: 'DESC', + }, + }, } - }); + ); } // This repository is read-only for now since creating own learning object is an extension feature. } diff --git a/backend/src/data/content/learning-object-repository.ts b/backend/src/data/content/learning-object-repository.ts index 8fdf18fe..f9b6bfcb 100644 --- a/backend/src/data/content/learning-object-repository.ts +++ b/backend/src/data/content/learning-object-repository.ts @@ -1,12 +1,10 @@ import { DwengoEntityRepository } from '../dwengo-entity-repository.js'; import { LearningObject } from '../../entities/content/learning-object.entity.js'; import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier.js'; -import {Language} from "../../entities/content/language"; +import { Language } from '../../entities/content/language'; export class LearningObjectRepository extends DwengoEntityRepository { - public findByIdentifier( - identifier: LearningObjectIdentifier - ): Promise { + public findByIdentifier(identifier: LearningObjectIdentifier): Promise { return this.findOne( { hruid: identifier.hruid, @@ -14,7 +12,7 @@ export class LearningObjectRepository extends DwengoEntityRepository { - public findByHruidAndLanguage( - hruid: string, - language: Language - ): Promise { - return this.findOne( - { hruid: hruid, language: language }, - { populate: ["nodes", "nodes.transitions"] } - ); + public findByHruidAndLanguage(hruid: string, language: Language): Promise { + return this.findOne({ hruid: hruid, language: language }, { populate: ['nodes', 'nodes.transitions'] }); } /** @@ -24,12 +18,9 @@ export class LearningPathRepository extends DwengoEntityRepository return this.findAll({ where: { language: language, - $or: [ - { title: { $like: `%${query}%`} }, - { description: { $like: `%${query}%`} } - ] + $or: [{ title: { $like: `%${query}%` } }, { description: { $like: `%${query}%` } }], }, - populate: ["nodes", "nodes.transitions"] + populate: ['nodes', 'nodes.transitions'], }); } } diff --git a/backend/src/data/repositories.ts b/backend/src/data/repositories.ts index 543de6e5..7901d928 100644 --- a/backend/src/data/repositories.ts +++ b/backend/src/data/repositories.ts @@ -28,8 +28,8 @@ import { LearningPath } from '../entities/content/learning-path.entity.js'; import { LearningPathRepository } from './content/learning-path-repository.js'; import { AttachmentRepository } from './content/attachment-repository.js'; import { Attachment } from '../entities/content/attachment.entity.js'; -import {LearningPathNode} from "../entities/content/learning-path-node.entity"; -import {LearningPathTransition} from "../entities/content/learning-path-transition.entity"; +import { LearningPathNode } from '../entities/content/learning-path-node.entity'; +import { LearningPathTransition } from '../entities/content/learning-path-transition.entity'; let entityManager: EntityManager | undefined; @@ -73,17 +73,8 @@ export const getQuestionRepository = repositoryGetter(Answer); /* Learning content */ -export const getLearningObjectRepository = repositoryGetter< - LearningObject, - LearningObjectRepository ->(LearningObject); -export const getLearningPathRepository = repositoryGetter< - LearningPath, - LearningPathRepository ->(LearningPath); +export const getLearningObjectRepository = repositoryGetter(LearningObject); +export const getLearningPathRepository = repositoryGetter(LearningPath); export const getLearningPathNodeRepository = repositoryGetter(LearningPathNode); export const getLearningPathTransitionRepository = repositoryGetter(LearningPathTransition); -export const getAttachmentRepository = repositoryGetter< - Attachment, - AttachmentRepository ->(Attachment); +export const getAttachmentRepository = repositoryGetter(Attachment); diff --git a/backend/src/entities/assignments/assignment.entity.ts b/backend/src/entities/assignments/assignment.entity.ts index 44bb6810..9e3f3b03 100644 --- a/backend/src/entities/assignments/assignment.entity.ts +++ b/backend/src/entities/assignments/assignment.entity.ts @@ -2,9 +2,9 @@ import { Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro import { Class } from '../classes/class.entity.js'; import { Group } from './group.entity.js'; import { Language } from '../content/language.js'; -import {AssignmentRepository} from "../../data/assignments/assignment-repository"; +import { AssignmentRepository } from '../../data/assignments/assignment-repository'; -@Entity({repository: () => AssignmentRepository}) +@Entity({ repository: () => AssignmentRepository }) export class Assignment { @ManyToOne({ entity: () => Class, primary: true }) within!: Class; diff --git a/backend/src/entities/assignments/group.entity.ts b/backend/src/entities/assignments/group.entity.ts index 0915b31b..7e01cf62 100644 --- a/backend/src/entities/assignments/group.entity.ts +++ b/backend/src/entities/assignments/group.entity.ts @@ -1,9 +1,9 @@ import { Entity, ManyToMany, ManyToOne, PrimaryKey } from '@mikro-orm/core'; import { Assignment } from './assignment.entity.js'; import { Student } from '../users/student.entity.js'; -import {GroupRepository} from "../../data/assignments/group-repository"; +import { GroupRepository } from '../../data/assignments/group-repository'; -@Entity({repository: () => GroupRepository}) +@Entity({ repository: () => GroupRepository }) export class Group { @ManyToOne({ entity: () => Assignment, diff --git a/backend/src/entities/assignments/submission.entity.ts b/backend/src/entities/assignments/submission.entity.ts index a5c2238b..34e0c1f6 100644 --- a/backend/src/entities/assignments/submission.entity.ts +++ b/backend/src/entities/assignments/submission.entity.ts @@ -2,9 +2,9 @@ import { Student } from '../users/student.entity.js'; import { Group } from './group.entity.js'; import { Entity, Enum, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'; import { Language } from '../content/language.js'; -import {SubmissionRepository} from "../../data/assignments/submission-repository"; +import { SubmissionRepository } from '../../data/assignments/submission-repository'; -@Entity({repository: () => SubmissionRepository}) +@Entity({ repository: () => SubmissionRepository }) export class Submission { @PrimaryKey({ type: 'string' }) learningObjectHruid!: string; diff --git a/backend/src/entities/classes/class-join-request.entity.ts b/backend/src/entities/classes/class-join-request.entity.ts index 5d9ef571..01197193 100644 --- a/backend/src/entities/classes/class-join-request.entity.ts +++ b/backend/src/entities/classes/class-join-request.entity.ts @@ -1,9 +1,9 @@ import { Entity, Enum, ManyToOne } from '@mikro-orm/core'; import { Student } from '../users/student.entity.js'; import { Class } from './class.entity.js'; -import {ClassJoinRequestRepository} from "../../data/classes/class-join-request-repository"; +import { ClassJoinRequestRepository } from '../../data/classes/class-join-request-repository'; -@Entity({repository: () => ClassJoinRequestRepository}) +@Entity({ repository: () => ClassJoinRequestRepository }) export class ClassJoinRequest { @ManyToOne({ entity: () => Student, diff --git a/backend/src/entities/classes/class.entity.ts b/backend/src/entities/classes/class.entity.ts index c430c9dc..610622cc 100644 --- a/backend/src/entities/classes/class.entity.ts +++ b/backend/src/entities/classes/class.entity.ts @@ -2,9 +2,9 @@ import { Collection, Entity, ManyToMany, PrimaryKey, Property } from '@mikro-orm import { v4 } from 'uuid'; import { Teacher } from '../users/teacher.entity.js'; import { Student } from '../users/student.entity.js'; -import {ClassRepository} from "../../data/classes/class-repository"; +import { ClassRepository } from '../../data/classes/class-repository'; -@Entity({repository: () => ClassRepository}) +@Entity({ repository: () => ClassRepository }) export class Class { @PrimaryKey() classId = v4(); diff --git a/backend/src/entities/classes/teacher-invitation.entity.ts b/backend/src/entities/classes/teacher-invitation.entity.ts index 597b6a41..e8bb8d01 100644 --- a/backend/src/entities/classes/teacher-invitation.entity.ts +++ b/backend/src/entities/classes/teacher-invitation.entity.ts @@ -1,12 +1,12 @@ import { Entity, ManyToOne } from '@mikro-orm/core'; import { Teacher } from '../users/teacher.entity.js'; import { Class } from './class.entity.js'; -import {TeacherInvitationRepository} from "../../data/classes/teacher-invitation-repository"; +import { TeacherInvitationRepository } from '../../data/classes/teacher-invitation-repository'; /** * Invitation of a teacher into a class (in order to teach it). */ -@Entity({repository: () => TeacherInvitationRepository}) +@Entity({ repository: () => TeacherInvitationRepository }) export class TeacherInvitation { @ManyToOne({ entity: () => Teacher, diff --git a/backend/src/entities/content/attachment.entity.ts b/backend/src/entities/content/attachment.entity.ts index 5e7000cf..f0a1b181 100644 --- a/backend/src/entities/content/attachment.entity.ts +++ b/backend/src/entities/content/attachment.entity.ts @@ -1,8 +1,8 @@ import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'; import { LearningObject } from './learning-object.entity.js'; -import {AttachmentRepository} from "../../data/content/attachment-repository"; +import { AttachmentRepository } from '../../data/content/attachment-repository'; -@Entity({repository: () => AttachmentRepository}) +@Entity({ repository: () => AttachmentRepository }) export class Attachment { @ManyToOne({ entity: () => LearningObject, diff --git a/backend/src/entities/content/language.ts b/backend/src/entities/content/language.ts index 7a106762..d7687331 100644 --- a/backend/src/entities/content/language.ts +++ b/backend/src/entities/content/language.ts @@ -182,5 +182,5 @@ export enum Language { Yiddish = 'yi', Yoruba = 'yo', Zhuang = 'za', - Zulu = 'zu' + Zulu = 'zu', } diff --git a/backend/src/entities/content/learning-object.entity.ts b/backend/src/entities/content/learning-object.entity.ts index 8f3672be..55c4a808 100644 --- a/backend/src/entities/content/learning-object.entity.ts +++ b/backend/src/entities/content/learning-object.entity.ts @@ -2,11 +2,11 @@ import { Embeddable, Embedded, Entity, Enum, ManyToMany, OneToMany, PrimaryKey, import { Language } from './language.js'; import { Attachment } from './attachment.entity.js'; import { Teacher } from '../users/teacher.entity.js'; -import {DwengoContentType} from "../../services/learning-objects/processing/content-type"; -import {v4} from "uuid"; -import {LearningObjectRepository} from "../../data/content/learning-object-repository"; +import { DwengoContentType } from '../../services/learning-objects/processing/content-type'; +import { v4 } from 'uuid'; +import { LearningObjectRepository } from '../../data/content/learning-object-repository'; -@Entity({repository: () => LearningObjectRepository}) +@Entity({ repository: () => LearningObjectRepository }) export class LearningObject { @PrimaryKey({ type: 'string' }) hruid!: string; @@ -20,7 +20,7 @@ export class LearningObject { @PrimaryKey({ type: 'number' }) version: number = 1; - @Property({type: 'uuid', unique: true}) + @Property({ type: 'uuid', unique: true }) uuid = v4(); @ManyToMany({ diff --git a/backend/src/entities/content/learning-path-node.entity.ts b/backend/src/entities/content/learning-path-node.entity.ts index e2fbdbb3..9dbb47b4 100644 --- a/backend/src/entities/content/learning-path-node.entity.ts +++ b/backend/src/entities/content/learning-path-node.entity.ts @@ -1,15 +1,14 @@ -import {Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property} from "@mikro-orm/core"; -import {Language} from "./language"; -import {LearningPath} from "./learning-path.entity"; -import {LearningPathTransition} from "./learning-path-transition.entity"; +import { Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'; +import { Language } from './language'; +import { LearningPath } from './learning-path.entity'; +import { LearningPathTransition } from './learning-path-transition.entity'; @Entity() export class LearningPathNode { - @ManyToOne({ entity: () => LearningPath, primary: true }) learningPath!: LearningPath; - @PrimaryKey({ type: "integer", autoincrement: true }) + @PrimaryKey({ type: 'integer', autoincrement: true }) nodeNumber!: number; @Property({ type: 'string' }) @@ -27,7 +26,7 @@ export class LearningPathNode { @Property({ type: 'bool' }) startNode!: boolean; - @OneToMany({ entity: () => LearningPathTransition, mappedBy: "node" }) + @OneToMany({ entity: () => LearningPathTransition, mappedBy: 'node' }) transitions: LearningPathTransition[] = []; @Property({ length: 3 }) diff --git a/backend/src/entities/content/learning-path-transition.entity.ts b/backend/src/entities/content/learning-path-transition.entity.ts index dfbe110e..97bfc65f 100644 --- a/backend/src/entities/content/learning-path-transition.entity.ts +++ b/backend/src/entities/content/learning-path-transition.entity.ts @@ -1,9 +1,9 @@ -import {Entity, ManyToOne, PrimaryKey, Property} from "@mikro-orm/core"; -import {LearningPathNode} from "./learning-path-node.entity"; +import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'; +import { LearningPathNode } from './learning-path-node.entity'; @Entity() export class LearningPathTransition { - @ManyToOne({entity: () => LearningPathNode, primary: true }) + @ManyToOne({ entity: () => LearningPathNode, primary: true }) node!: LearningPathNode; @PrimaryKey({ type: 'numeric' }) diff --git a/backend/src/entities/content/learning-path.entity.ts b/backend/src/entities/content/learning-path.entity.ts index 3bb839a0..e74388aa 100644 --- a/backend/src/entities/content/learning-path.entity.ts +++ b/backend/src/entities/content/learning-path.entity.ts @@ -1,16 +1,10 @@ -import { - Entity, - Enum, - ManyToMany, OneToMany, - PrimaryKey, - Property, -} from '@mikro-orm/core'; +import { Entity, Enum, ManyToMany, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'; import { Language } from './language.js'; import { Teacher } from '../users/teacher.entity.js'; -import {LearningPathRepository} from "../../data/content/learning-path-repository"; -import {LearningPathNode} from "./learning-path-node.entity"; +import { LearningPathRepository } from '../../data/content/learning-path-repository'; +import { LearningPathNode } from './learning-path-node.entity'; -@Entity({repository: () => LearningPathRepository}) +@Entity({ repository: () => LearningPathRepository }) export class LearningPath { @PrimaryKey({ type: 'string' }) hruid!: string; @@ -30,6 +24,6 @@ export class LearningPath { @Property({ type: 'blob', nullable: true }) image: Buffer | null = null; - @OneToMany({ entity: () => LearningPathNode, mappedBy: "learningPath" }) + @OneToMany({ entity: () => LearningPathNode, mappedBy: 'learningPath' }) nodes: LearningPathNode[] = []; } diff --git a/backend/src/entities/questions/answer.entity.ts b/backend/src/entities/questions/answer.entity.ts index 81974943..2c975cc5 100644 --- a/backend/src/entities/questions/answer.entity.ts +++ b/backend/src/entities/questions/answer.entity.ts @@ -1,9 +1,9 @@ import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'; import { Question } from './question.entity.js'; import { Teacher } from '../users/teacher.entity.js'; -import {AnswerRepository} from "../../data/questions/answer-repository"; +import { AnswerRepository } from '../../data/questions/answer-repository'; -@Entity({repository: () => AnswerRepository}) +@Entity({ repository: () => AnswerRepository }) export class Answer { @ManyToOne({ entity: () => Teacher, diff --git a/backend/src/entities/questions/question.entity.ts b/backend/src/entities/questions/question.entity.ts index c03b0e8f..bfa0d7bb 100644 --- a/backend/src/entities/questions/question.entity.ts +++ b/backend/src/entities/questions/question.entity.ts @@ -1,9 +1,9 @@ import { Entity, Enum, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'; import { Language } from '../content/language.js'; import { Student } from '../users/student.entity.js'; -import {QuestionRepository} from "../../data/questions/question-repository"; +import { QuestionRepository } from '../../data/questions/question-repository'; -@Entity({repository: () => QuestionRepository}) +@Entity({ repository: () => QuestionRepository }) export class Question { @PrimaryKey({ type: 'string' }) learningObjectHruid!: string; diff --git a/backend/src/entities/users/teacher.entity.ts b/backend/src/entities/users/teacher.entity.ts index ca3290bf..8af72c37 100644 --- a/backend/src/entities/users/teacher.entity.ts +++ b/backend/src/entities/users/teacher.entity.ts @@ -1,9 +1,9 @@ import { Collection, Entity, ManyToMany } from '@mikro-orm/core'; import { User } from './user.entity.js'; import { Class } from '../classes/class.entity.js'; -import {TeacherRepository} from "../../data/users/teacher-repository"; +import { TeacherRepository } from '../../data/users/teacher-repository'; -@Entity({repository: () => TeacherRepository}) +@Entity({ repository: () => TeacherRepository }) export class Teacher extends User { @ManyToMany(() => Class) classes!: Collection; diff --git a/backend/src/interfaces/learning-content.ts b/backend/src/interfaces/learning-content.ts index 5d11d6b2..970796a2 100644 --- a/backend/src/interfaces/learning-content.ts +++ b/backend/src/interfaces/learning-content.ts @@ -1,4 +1,4 @@ -import {Language} from "../entities/content/language"; +import { Language } from '../entities/content/language'; export interface Transition { default: boolean; diff --git a/backend/src/routes/learning-objects.ts b/backend/src/routes/learning-objects.ts index 421a5f19..b731fe69 100644 --- a/backend/src/routes/learning-objects.ts +++ b/backend/src/routes/learning-objects.ts @@ -1,8 +1,5 @@ import express from 'express'; -import { - getAllLearningObjects, getAttachment, - getLearningObject, getLearningObjectHTML, -} from '../controllers/learning-objects.js'; +import { getAllLearningObjects, getAttachment, getLearningObject, getLearningObjectHTML } from '../controllers/learning-objects.js'; const router = express.Router(); diff --git a/backend/src/services/learning-objects/attachment-service.ts b/backend/src/services/learning-objects/attachment-service.ts index fb2b2dd2..7791ac04 100644 --- a/backend/src/services/learning-objects/attachment-service.ts +++ b/backend/src/services/learning-objects/attachment-service.ts @@ -1,21 +1,23 @@ -import {getAttachmentRepository} from "../../data/repositories"; -import {Attachment} from "../../entities/content/attachment.entity"; -import {LearningObjectIdentifier} from "../../interfaces/learning-content"; +import { getAttachmentRepository } from '../../data/repositories'; +import { Attachment } from '../../entities/content/attachment.entity'; +import { LearningObjectIdentifier } from '../../interfaces/learning-content'; const attachmentService = { getAttachment(learningObjectId: LearningObjectIdentifier, attachmentName: string): Promise { const attachmentRepo = getAttachmentRepository(); if (learningObjectId.version) { - return attachmentRepo.findByLearningObjectIdAndName({ - hruid: learningObjectId.hruid, - language: learningObjectId.language, - version: learningObjectId.version, - }, attachmentName); - } - return attachmentRepo.findByMostRecentVersionOfLearningObjectAndName(learningObjectId.hruid, learningObjectId.language, attachmentName); - - } -} + return attachmentRepo.findByLearningObjectIdAndName( + { + hruid: learningObjectId.hruid, + language: learningObjectId.language, + version: learningObjectId.version, + }, + attachmentName + ); + } + return attachmentRepo.findByMostRecentVersionOfLearningObjectAndName(learningObjectId.hruid, learningObjectId.language, attachmentName); + }, +}; export default attachmentService; diff --git a/backend/src/services/learning-objects/database-learning-object-provider.ts b/backend/src/services/learning-objects/database-learning-object-provider.ts index 46fc23fe..533d382f 100644 --- a/backend/src/services/learning-objects/database-learning-object-provider.ts +++ b/backend/src/services/learning-objects/database-learning-object-provider.ts @@ -1,16 +1,11 @@ -import {LearningObjectProvider} from "./learning-object-provider"; -import { - FilteredLearningObject, - LearningObjectIdentifier, - LearningPathIdentifier -} from "../../interfaces/learning-content"; -import {getLearningObjectRepository, getLearningPathRepository} from "../../data/repositories"; -import {Language} from "../../entities/content/language"; -import {LearningObject} from "../../entities/content/learning-object.entity"; -import {getUrlStringForLearningObject} from "../../util/links"; -import processingService from "./processing/processing-service"; -import {NotFoundError} from "@mikro-orm/core"; - +import { LearningObjectProvider } from './learning-object-provider'; +import { FilteredLearningObject, LearningObjectIdentifier, LearningPathIdentifier } from '../../interfaces/learning-content'; +import { getLearningObjectRepository, getLearningPathRepository } from '../../data/repositories'; +import { Language } from '../../entities/content/language'; +import { LearningObject } from '../../entities/content/learning-object.entity'; +import { getUrlStringForLearningObject } from '../../util/links'; +import processingService from './processing/processing-service'; +import { NotFoundError } from '@mikro-orm/core'; function convertLearningObject(learningObject: LearningObject | null): FilteredLearningObject | null { if (!learningObject) { @@ -34,20 +29,18 @@ function convertLearningObject(learningObject: LearningObject | null): FilteredL educationalGoals: learningObject.educationalGoals, returnValue: { callback_url: learningObject.returnValue.callbackUrl, - callback_schema: JSON.parse(learningObject.returnValue.callbackSchema) + callback_schema: JSON.parse(learningObject.returnValue.callbackSchema), }, skosConcepts: learningObject.skosConcepts, targetAges: learningObject.targetAges || [], - teacherExclusive: learningObject.teacherExclusive - } + teacherExclusive: learningObject.teacherExclusive, + }; } function findLearningObjectEntityById(id: LearningObjectIdentifier): Promise { const learningObjectRepo = getLearningObjectRepository(); - return learningObjectRepo.findLatestByHruidAndLanguage( - id.hruid, id.language as Language - ); + return learningObjectRepo.findLatestByHruidAndLanguage(id.hruid, id.language as Language); } /** @@ -68,16 +61,11 @@ const databaseLearningObjectProvider: LearningObjectProvider = { async getLearningObjectHTML(id: LearningObjectIdentifier): Promise { const learningObjectRepo = getLearningObjectRepository(); - const learningObject = await learningObjectRepo.findLatestByHruidAndLanguage( - id.hruid, id.language as Language - ); + const learningObject = await learningObjectRepo.findLatestByHruidAndLanguage(id.hruid, id.language as Language); if (!learningObject) { return null; } - return await processingService.render( - learningObject, - (id) => findLearningObjectEntityById(id) - ); + return await processingService.render(learningObject, (id) => findLearningObjectEntityById(id)); }, /** @@ -88,9 +76,9 @@ const databaseLearningObjectProvider: LearningObjectProvider = { const learningPath = await learningPathRepo.findByHruidAndLanguage(id.hruid, id.language); if (!learningPath) { - throw new NotFoundError("The learning path with the given ID could not be found."); + throw new NotFoundError('The learning path with the given ID could not be found.'); } - return learningPath.nodes.map(it => it.learningObjectHruid); // TODO: Determine this based on the submissions of the user. + return learningPath.nodes.map((it) => it.learningObjectHruid); // TODO: Determine this based on the submissions of the user. }, /** @@ -101,23 +89,23 @@ const databaseLearningObjectProvider: LearningObjectProvider = { const learningPath = await learningPathRepo.findByHruidAndLanguage(id.hruid, id.language); if (!learningPath) { - throw new NotFoundError("The learning path with the given ID could not be found."); + throw new NotFoundError('The learning path with the given ID could not be found.'); } const learningObjects = await Promise.all( - learningPath.nodes.map(it => { + learningPath.nodes.map((it) => { const learningObject = this.getLearningObjectById({ hruid: it.learningObjectHruid, language: it.language, - version: it.version - }) + version: it.version, + }); if (learningObject === null) { console.log(`WARN: Learning object corresponding with node ${it} not found!`); } return learningObject; }) ); - return learningObjects.filter(it => it !== null); // TODO: Determine this based on the submissions of the user. - } -} + return learningObjects.filter((it) => it !== null); // TODO: Determine this based on the submissions of the user. + }, +}; export default databaseLearningObjectProvider; diff --git a/backend/src/services/learning-objects/dwengo-api-learning-object-provider.ts b/backend/src/services/learning-objects/dwengo-api-learning-object-provider.ts index ab914be4..c59a3616 100644 --- a/backend/src/services/learning-objects/dwengo-api-learning-object-provider.ts +++ b/backend/src/services/learning-objects/dwengo-api-learning-object-provider.ts @@ -1,22 +1,22 @@ import { DWENGO_API_BASE } from '../../config.js'; import { fetchWithLogging } from '../../util/apiHelper.js'; import { - FilteredLearningObject, LearningObjectIdentifier, + FilteredLearningObject, + LearningObjectIdentifier, LearningObjectMetadata, - LearningObjectNode, LearningPathIdentifier, + LearningObjectNode, + LearningPathIdentifier, LearningPathResponse, } from '../../interfaces/learning-content.js'; import dwengoApiLearningPathProvider from '../learning-paths/dwengo-api-learning-path-provider.js'; -import {LearningObjectProvider} from "./learning-object-provider"; +import { LearningObjectProvider } from './learning-object-provider'; /** * Helper function to convert the learning object metadata retrieved from the API to a FilteredLearningObject which * our API should return. * @param data */ -function filterData( - data: LearningObjectMetadata -): FilteredLearningObject { +function filterData(data: LearningObjectMetadata): FilteredLearningObject { return { key: data.hruid, // Hruid learningObject (not path) _id: data._id, @@ -43,25 +43,16 @@ function filterData( /** * Generic helper function to fetch all learning objects from a given path (full data or just HRUIDs) */ -async function fetchLearningObjects( - learningPathId: LearningPathIdentifier, - full: boolean -): Promise { +async function fetchLearningObjects(learningPathId: LearningPathIdentifier, full: boolean): Promise { try { - const learningPathResponse: LearningPathResponse = - await dwengoApiLearningPathProvider.fetchLearningPaths( - [learningPathId.hruid], - learningPathId.language, - `Learning path for HRUID "${learningPathId.hruid}"` - ); + const learningPathResponse: LearningPathResponse = await dwengoApiLearningPathProvider.fetchLearningPaths( + [learningPathId.hruid], + learningPathId.language, + `Learning path for HRUID "${learningPathId.hruid}"` + ); - if ( - !learningPathResponse.success || - !learningPathResponse.data?.length - ) { - console.error( - `⚠️ WARNING: Learning path "${learningPathId.hruid}" exists but contains no learning objects.` - ); + if (!learningPathResponse.success || !learningPathResponse.data?.length) { + console.error(`⚠️ WARNING: Learning path "${learningPathId.hruid}" exists but contains no learning objects.`); return []; } @@ -72,10 +63,12 @@ async function fetchLearningObjects( } return await Promise.all( - nodes.map(async (node) => dwengoApiLearningObjectProvider.getLearningObjectById({ + nodes.map(async (node) => + dwengoApiLearningObjectProvider.getLearningObjectById({ hruid: node.learningobject_hruid, - language: learningPathId.language - })) + language: learningPathId.language, + }) + ) ).then((objects) => objects.filter((obj): obj is FilteredLearningObject => obj !== null)); } catch (error) { console.error('❌ Error fetching learning objects:', error); @@ -87,19 +80,17 @@ const dwengoApiLearningObjectProvider: LearningObjectProvider = { /** * Fetches a single learning object by its HRUID */ - async getLearningObjectById( - id: LearningObjectIdentifier - ): Promise { + async getLearningObjectById(id: LearningObjectIdentifier): Promise { const metadataUrl = `${DWENGO_API_BASE}/learningObject/getMetadata`; const metadata = await fetchWithLogging( metadataUrl, `Metadata for Learning Object HRUID "${id.hruid}" (language ${id.language})`, { - params: id + params: id, } ); - if (!metadata || typeof metadata !== "object") { + if (!metadata || typeof metadata !== 'object') { console.error(`⚠️ WARNING: Learning object "${id.hruid}" not found.`); return null; } @@ -111,10 +102,7 @@ const dwengoApiLearningObjectProvider: LearningObjectProvider = { * Fetch full learning object data (metadata) */ async getLearningObjectsFromPath(id: LearningPathIdentifier): Promise { - return (await fetchLearningObjects( - id, - true, - )) as FilteredLearningObject[]; + return (await fetchLearningObjects(id, true)) as FilteredLearningObject[]; }, /** @@ -130,13 +118,9 @@ const dwengoApiLearningObjectProvider: LearningObjectProvider = { */ async getLearningObjectHTML(id: LearningObjectIdentifier): Promise { const htmlUrl = `${DWENGO_API_BASE}/learningObject/getRaw`; - const html = await fetchWithLogging( - htmlUrl, - `Metadata for Learning Object HRUID "${id.hruid}" (language ${id.language})`, - { - params: id - } - ); + const html = await fetchWithLogging(htmlUrl, `Metadata for Learning Object HRUID "${id.hruid}" (language ${id.language})`, { + params: id, + }); if (!html) { console.error(`⚠️ WARNING: Learning object "${id.hruid}" not found.`); @@ -144,7 +128,7 @@ const dwengoApiLearningObjectProvider: LearningObjectProvider = { } return html; - } + }, }; export default dwengoApiLearningObjectProvider; diff --git a/backend/src/services/learning-objects/learning-object-provider.ts b/backend/src/services/learning-objects/learning-object-provider.ts index 70190a1a..4d443ca0 100644 --- a/backend/src/services/learning-objects/learning-object-provider.ts +++ b/backend/src/services/learning-objects/learning-object-provider.ts @@ -1,8 +1,4 @@ -import { - FilteredLearningObject, - LearningObjectIdentifier, - LearningPathIdentifier -} from "../../interfaces/learning-content"; +import { FilteredLearningObject, LearningObjectIdentifier, LearningPathIdentifier } from '../../interfaces/learning-content'; export interface LearningObjectProvider { /** diff --git a/backend/src/services/learning-objects/learning-object-service.ts b/backend/src/services/learning-objects/learning-object-service.ts index 9dd327f0..b207d3dc 100644 --- a/backend/src/services/learning-objects/learning-object-service.ts +++ b/backend/src/services/learning-objects/learning-object-service.ts @@ -1,19 +1,14 @@ -import { - FilteredLearningObject, - LearningObjectIdentifier, - LearningPathIdentifier -} from "../../interfaces/learning-content"; -import dwengoApiLearningObjectProvider from "./dwengo-api-learning-object-provider"; -import {LearningObjectProvider} from "./learning-object-provider"; -import {EnvVars, getEnvVar} from "../../util/envvars"; -import databaseLearningObjectProvider from "./database-learning-object-provider"; +import { FilteredLearningObject, LearningObjectIdentifier, LearningPathIdentifier } from '../../interfaces/learning-content'; +import dwengoApiLearningObjectProvider from './dwengo-api-learning-object-provider'; +import { LearningObjectProvider } from './learning-object-provider'; +import { EnvVars, getEnvVar } from '../../util/envvars'; +import databaseLearningObjectProvider from './database-learning-object-provider'; function getProvider(id: LearningObjectIdentifier): LearningObjectProvider { if (id.hruid.startsWith(getEnvVar(EnvVars.UserContentPrefix))) { return databaseLearningObjectProvider; - } - return dwengoApiLearningObjectProvider; - + } + return dwengoApiLearningObjectProvider; } /** @@ -46,7 +41,7 @@ const learningObjectService = { */ getLearningObjectHTML(id: LearningObjectIdentifier): Promise { return getProvider(id).getLearningObjectHTML(id); - } + }, }; export default learningObjectService; diff --git a/backend/src/services/learning-objects/processing/audio/audio-processor.ts b/backend/src/services/learning-objects/processing/audio/audio-processor.ts index 0c4dd75e..3f7a8837 100644 --- a/backend/src/services/learning-objects/processing/audio/audio-processor.ts +++ b/backend/src/services/learning-objects/processing/audio/audio-processor.ts @@ -5,12 +5,11 @@ */ import DOMPurify from 'isomorphic-dompurify'; -import {type} from "node:os"; -import {DwengoContentType} from "../content-type"; -import {StringProcessor} from "../string-processor"; +import { type } from 'node:os'; +import { DwengoContentType } from '../content-type'; +import { StringProcessor } from '../string-processor'; class AudioProcessor extends StringProcessor { - constructor() { super(DwengoContentType.AUDIO_MPEG); } diff --git a/backend/src/services/learning-objects/processing/content-type.ts b/backend/src/services/learning-objects/processing/content-type.ts index d71c97b4..2ea44246 100644 --- a/backend/src/services/learning-objects/processing/content-type.ts +++ b/backend/src/services/learning-objects/processing/content-type.ts @@ -3,16 +3,16 @@ */ enum DwengoContentType { - TEXT_PLAIN = "text/plain", - TEXT_MARKDOWN = "text/markdown", - IMAGE_BLOCK = "image/image-block", - IMAGE_INLINE = "image/image", - AUDIO_MPEG = "audio/mpeg", - APPLICATION_PDF = "application/pdf", - EXTERN = "extern", - BLOCKLY = "blockly", - GIFT = "text/gift", - CT_SCHEMA = "text/ct-schema" + TEXT_PLAIN = 'text/plain', + TEXT_MARKDOWN = 'text/markdown', + IMAGE_BLOCK = 'image/image-block', + IMAGE_INLINE = 'image/image', + AUDIO_MPEG = 'audio/mpeg', + APPLICATION_PDF = 'application/pdf', + EXTERN = 'extern', + BLOCKLY = 'blockly', + GIFT = 'text/gift', + CT_SCHEMA = 'text/ct-schema', } -export { DwengoContentType } +export { DwengoContentType }; diff --git a/backend/src/services/learning-objects/processing/extern/extern-processor.ts b/backend/src/services/learning-objects/processing/extern/extern-processor.ts index 68ec9899..d16445dc 100644 --- a/backend/src/services/learning-objects/processing/extern/extern-processor.ts +++ b/backend/src/services/learning-objects/processing/extern/extern-processor.ts @@ -5,10 +5,10 @@ */ import DOMPurify from 'isomorphic-dompurify'; -import {ProcessingError} from "../processing-error"; -import {isValidHttpUrl} from "../../../../util/links"; -import {DwengoContentType} from "../content-type"; -import {StringProcessor} from "../string-processor"; +import { ProcessingError } from '../processing-error'; +import { isValidHttpUrl } from '../../../../util/links'; +import { DwengoContentType } from '../content-type'; +import { StringProcessor } from '../string-processor'; class ExternProcessor extends StringProcessor { constructor() { @@ -17,23 +17,23 @@ class ExternProcessor extends StringProcessor { override renderFn(externURL: string) { if (!isValidHttpUrl(externURL)) { - throw new ProcessingError("The url is not valid: " + externURL); + throw new ProcessingError('The url is not valid: ' + externURL); } // If a seperate youtube-processor would be added, this code would need to move to that processor // Converts youtube urls to youtube-embed urls - const match = /(.*youtube.com\/)watch\?v=(.*)/.exec(externURL) + const match = /(.*youtube.com\/)watch\?v=(.*)/.exec(externURL); if (match) { - externURL = match[1] + "embed/" + match[2]; + externURL = match[1] + 'embed/' + match[2]; } - return DOMPurify.sanitize(` + return DOMPurify.sanitize( + `
`, - { ADD_TAGS: ["iframe"], ADD_ATTR: ['allow', 'allowfullscreen', 'frameborder', 'scrolling']} + { ADD_TAGS: ['iframe'], ADD_ATTR: ['allow', 'allowfullscreen', 'frameborder', 'scrolling'] } ); - } } diff --git a/backend/src/services/learning-objects/processing/gift/gift-processor.ts b/backend/src/services/learning-objects/processing/gift/gift-processor.ts index b6eba8ba..49f41904 100644 --- a/backend/src/services/learning-objects/processing/gift/gift-processor.ts +++ b/backend/src/services/learning-objects/processing/gift/gift-processor.ts @@ -3,21 +3,20 @@ */ import DOMPurify from 'isomorphic-dompurify'; -import {GIFTQuestion, parse} from "gift-pegjs" -import {DwengoContentType} from "../content-type"; -import {GIFTQuestionRenderer} from "./question-renderers/gift-question-renderer"; -import {MultipleChoiceQuestionRenderer} from "./question-renderers/multiple-choice-question-renderer"; -import {CategoryQuestionRenderer} from "./question-renderers/category-question-renderer"; -import {DescriptionQuestionRenderer} from "./question-renderers/description-question-renderer"; -import {EssayQuestionRenderer} from "./question-renderers/essay-question-renderer"; -import {MatchingQuestionRenderer} from "./question-renderers/matching-question-renderer"; -import {NumericalQuestionRenderer} from "./question-renderers/numerical-question-renderer"; -import {ShortQuestionRenderer} from "./question-renderers/short-question-renderer"; -import {TrueFalseQuestionRenderer} from "./question-renderers/true-false-question-renderer"; -import {StringProcessor} from "../string-processor"; +import { GIFTQuestion, parse } from 'gift-pegjs'; +import { DwengoContentType } from '../content-type'; +import { GIFTQuestionRenderer } from './question-renderers/gift-question-renderer'; +import { MultipleChoiceQuestionRenderer } from './question-renderers/multiple-choice-question-renderer'; +import { CategoryQuestionRenderer } from './question-renderers/category-question-renderer'; +import { DescriptionQuestionRenderer } from './question-renderers/description-question-renderer'; +import { EssayQuestionRenderer } from './question-renderers/essay-question-renderer'; +import { MatchingQuestionRenderer } from './question-renderers/matching-question-renderer'; +import { NumericalQuestionRenderer } from './question-renderers/numerical-question-renderer'; +import { ShortQuestionRenderer } from './question-renderers/short-question-renderer'; +import { TrueFalseQuestionRenderer } from './question-renderers/true-false-question-renderer'; +import { StringProcessor } from '../string-processor'; class GiftProcessor extends StringProcessor { - private renderers: RendererMap = { Category: new CategoryQuestionRenderer(), Description: new DescriptionQuestionRenderer(), @@ -26,8 +25,8 @@ class GiftProcessor extends StringProcessor { Numerical: new NumericalQuestionRenderer(), Short: new ShortQuestionRenderer(), TF: new TrueFalseQuestionRenderer(), - MC: new MultipleChoiceQuestionRenderer() - } + MC: new MultipleChoiceQuestionRenderer(), + }; constructor() { super(DwengoContentType.GIFT); @@ -40,11 +39,11 @@ class GiftProcessor extends StringProcessor { let i = 1; for (const question of quizQuestions) { html += `
\n`; - html += " " + this.renderQuestion(question, i).replaceAll(/\n(.+)/g, "\n $1"); // Replace for indentation. + html += ' ' + this.renderQuestion(question, i).replaceAll(/\n(.+)/g, '\n $1'); // Replace for indentation. html += `
\n`; i++; } - html += "
\n" + html += '
\n'; return DOMPurify.sanitize(html); } @@ -56,7 +55,7 @@ class GiftProcessor extends StringProcessor { } type RendererMap = { - [K in GIFTQuestion["type"]]: GIFTQuestionRenderer> + [K in GIFTQuestion['type']]: GIFTQuestionRenderer>; }; export default GiftProcessor; diff --git a/backend/src/services/learning-objects/processing/gift/question-renderers/category-question-renderer.ts b/backend/src/services/learning-objects/processing/gift/question-renderers/category-question-renderer.ts index 6f299c17..2ed79087 100644 --- a/backend/src/services/learning-objects/processing/gift/question-renderers/category-question-renderer.ts +++ b/backend/src/services/learning-objects/processing/gift/question-renderers/category-question-renderer.ts @@ -1,6 +1,6 @@ -import {GIFTQuestionRenderer} from "./gift-question-renderer"; -import {Category} from "gift-pegjs"; -import {ProcessingError} from "../../processing-error"; +import { GIFTQuestionRenderer } from './gift-question-renderer'; +import { Category } from 'gift-pegjs'; +import { ProcessingError } from '../../processing-error'; export class CategoryQuestionRenderer extends GIFTQuestionRenderer { render(question: Category, questionNumber: number): string { diff --git a/backend/src/services/learning-objects/processing/gift/question-renderers/description-question-renderer.ts b/backend/src/services/learning-objects/processing/gift/question-renderers/description-question-renderer.ts index adea25a6..c9302e5a 100644 --- a/backend/src/services/learning-objects/processing/gift/question-renderers/description-question-renderer.ts +++ b/backend/src/services/learning-objects/processing/gift/question-renderers/description-question-renderer.ts @@ -1,6 +1,6 @@ -import {GIFTQuestionRenderer} from "./gift-question-renderer"; -import {Description} from "gift-pegjs"; -import {ProcessingError} from "../../processing-error"; +import { GIFTQuestionRenderer } from './gift-question-renderer'; +import { Description } from 'gift-pegjs'; +import { ProcessingError } from '../../processing-error'; export class DescriptionQuestionRenderer extends GIFTQuestionRenderer { render(question: Description, questionNumber: number): string { diff --git a/backend/src/services/learning-objects/processing/gift/question-renderers/essay-question-renderer.ts b/backend/src/services/learning-objects/processing/gift/question-renderers/essay-question-renderer.ts index af000c11..ed4b1c50 100644 --- a/backend/src/services/learning-objects/processing/gift/question-renderers/essay-question-renderer.ts +++ b/backend/src/services/learning-objects/processing/gift/question-renderers/essay-question-renderer.ts @@ -1,9 +1,9 @@ -import {GIFTQuestionRenderer} from "./gift-question-renderer"; -import {Essay} from "gift-pegjs"; +import { GIFTQuestionRenderer } from './gift-question-renderer'; +import { Essay } from 'gift-pegjs'; export class EssayQuestionRenderer extends GIFTQuestionRenderer { render(question: Essay, questionNumber: number): string { - let renderedHtml = ""; + let renderedHtml = ''; if (question.title) { renderedHtml += `

${question.title}

\n`; } diff --git a/backend/src/services/learning-objects/processing/gift/question-renderers/gift-question-renderer.ts b/backend/src/services/learning-objects/processing/gift/question-renderers/gift-question-renderer.ts index bd33107b..41ab5ba2 100644 --- a/backend/src/services/learning-objects/processing/gift/question-renderers/gift-question-renderer.ts +++ b/backend/src/services/learning-objects/processing/gift/question-renderers/gift-question-renderer.ts @@ -1,4 +1,4 @@ -import {GIFTQuestion} from "gift-pegjs"; +import { GIFTQuestion } from 'gift-pegjs'; /** * Subclasses of this class are renderers which can render a specific type of GIFT questions to HTML. diff --git a/backend/src/services/learning-objects/processing/gift/question-renderers/matching-question-renderer.ts b/backend/src/services/learning-objects/processing/gift/question-renderers/matching-question-renderer.ts index 93e7511e..302f44d3 100644 --- a/backend/src/services/learning-objects/processing/gift/question-renderers/matching-question-renderer.ts +++ b/backend/src/services/learning-objects/processing/gift/question-renderers/matching-question-renderer.ts @@ -1,6 +1,6 @@ -import {GIFTQuestionRenderer} from "./gift-question-renderer"; -import {Matching} from "gift-pegjs"; -import {ProcessingError} from "../../processing-error"; +import { GIFTQuestionRenderer } from './gift-question-renderer'; +import { Matching } from 'gift-pegjs'; +import { ProcessingError } from '../../processing-error'; export class MatchingQuestionRenderer extends GIFTQuestionRenderer { render(question: Matching, questionNumber: number): string { diff --git a/backend/src/services/learning-objects/processing/gift/question-renderers/multiple-choice-question-renderer.ts b/backend/src/services/learning-objects/processing/gift/question-renderers/multiple-choice-question-renderer.ts index bf1de8c4..26eac034 100644 --- a/backend/src/services/learning-objects/processing/gift/question-renderers/multiple-choice-question-renderer.ts +++ b/backend/src/services/learning-objects/processing/gift/question-renderers/multiple-choice-question-renderer.ts @@ -1,9 +1,9 @@ -import {GIFTQuestionRenderer} from "./gift-question-renderer"; -import {MultipleChoice} from "gift-pegjs"; +import { GIFTQuestionRenderer } from './gift-question-renderer'; +import { MultipleChoice } from 'gift-pegjs'; export class MultipleChoiceQuestionRenderer extends GIFTQuestionRenderer { render(question: MultipleChoice, questionNumber: number): string { - let renderedHtml = ""; + let renderedHtml = ''; if (question.title) { renderedHtml += `

${question.title}

\n`; } diff --git a/backend/src/services/learning-objects/processing/gift/question-renderers/numerical-question-renderer.ts b/backend/src/services/learning-objects/processing/gift/question-renderers/numerical-question-renderer.ts index 6553add4..65352795 100644 --- a/backend/src/services/learning-objects/processing/gift/question-renderers/numerical-question-renderer.ts +++ b/backend/src/services/learning-objects/processing/gift/question-renderers/numerical-question-renderer.ts @@ -1,6 +1,6 @@ -import {GIFTQuestionRenderer} from "./gift-question-renderer"; -import {Numerical} from "gift-pegjs"; -import {ProcessingError} from "../../processing-error"; +import { GIFTQuestionRenderer } from './gift-question-renderer'; +import { Numerical } from 'gift-pegjs'; +import { ProcessingError } from '../../processing-error'; export class NumericalQuestionRenderer extends GIFTQuestionRenderer { render(question: Numerical, questionNumber: number): string { diff --git a/backend/src/services/learning-objects/processing/gift/question-renderers/short-question-renderer.ts b/backend/src/services/learning-objects/processing/gift/question-renderers/short-question-renderer.ts index 96196a67..683bbc09 100644 --- a/backend/src/services/learning-objects/processing/gift/question-renderers/short-question-renderer.ts +++ b/backend/src/services/learning-objects/processing/gift/question-renderers/short-question-renderer.ts @@ -1,6 +1,6 @@ -import {GIFTQuestionRenderer} from "./gift-question-renderer"; -import {ShortAnswer} from "gift-pegjs"; -import {ProcessingError} from "../../processing-error"; +import { GIFTQuestionRenderer } from './gift-question-renderer'; +import { ShortAnswer } from 'gift-pegjs'; +import { ProcessingError } from '../../processing-error'; export class ShortQuestionRenderer extends GIFTQuestionRenderer { render(question: ShortAnswer, questionNumber: number): string { diff --git a/backend/src/services/learning-objects/processing/gift/question-renderers/true-false-question-renderer.ts b/backend/src/services/learning-objects/processing/gift/question-renderers/true-false-question-renderer.ts index 0ff108f4..7f0fb9f8 100644 --- a/backend/src/services/learning-objects/processing/gift/question-renderers/true-false-question-renderer.ts +++ b/backend/src/services/learning-objects/processing/gift/question-renderers/true-false-question-renderer.ts @@ -1,6 +1,6 @@ -import {GIFTQuestionRenderer} from "./gift-question-renderer"; -import {TrueFalse} from "gift-pegjs"; -import {ProcessingError} from "../../processing-error"; +import { GIFTQuestionRenderer } from './gift-question-renderer'; +import { TrueFalse } from 'gift-pegjs'; +import { ProcessingError } from '../../processing-error'; export class TrueFalseQuestionRenderer extends GIFTQuestionRenderer { render(question: TrueFalse, questionNumber: number): string { diff --git a/backend/src/services/learning-objects/processing/image/block-image-processor.ts b/backend/src/services/learning-objects/processing/image/block-image-processor.ts index 7d578e1c..f4f8a773 100644 --- a/backend/src/services/learning-objects/processing/image/block-image-processor.ts +++ b/backend/src/services/learning-objects/processing/image/block-image-processor.ts @@ -2,15 +2,15 @@ * Based on https://github.com/dwengovzw/Learning-Object-Repository/blob/main/app/processors/image/block_image_processor.js */ -import InlineImageProcessor from "./inline-image-processor.js" +import InlineImageProcessor from './inline-image-processor.js'; import DOMPurify from 'isomorphic-dompurify'; class BlockImageProcessor extends InlineImageProcessor { - constructor(){ + constructor() { super(); } - override renderFn(imageUrl: string){ + override renderFn(imageUrl: string) { const inlineHtml = super.render(imageUrl); return DOMPurify.sanitize(`
${inlineHtml}
`); } diff --git a/backend/src/services/learning-objects/processing/image/inline-image-processor.ts b/backend/src/services/learning-objects/processing/image/inline-image-processor.ts index 7815fab3..8d44d1ae 100644 --- a/backend/src/services/learning-objects/processing/image/inline-image-processor.ts +++ b/backend/src/services/learning-objects/processing/image/inline-image-processor.ts @@ -3,10 +3,10 @@ */ import DOMPurify from 'isomorphic-dompurify'; -import {DwengoContentType} from "../content-type.js"; -import {ProcessingError} from "../processing-error.js"; -import {isValidHttpUrl} from "../../../../util/links"; -import {StringProcessor} from "../string-processor"; +import { DwengoContentType } from '../content-type.js'; +import { ProcessingError } from '../processing-error.js'; +import { isValidHttpUrl } from '../../../../util/links'; +import { StringProcessor } from '../string-processor'; class InlineImageProcessor extends StringProcessor { constructor(contentType: DwengoContentType = DwengoContentType.IMAGE_INLINE) { diff --git a/backend/src/services/learning-objects/processing/markdown/dwengo-marked-renderer.ts b/backend/src/services/learning-objects/processing/markdown/dwengo-marked-renderer.ts index d5324754..96710591 100644 --- a/backend/src/services/learning-objects/processing/markdown/dwengo-marked-renderer.ts +++ b/backend/src/services/learning-objects/processing/markdown/dwengo-marked-renderer.ts @@ -1,15 +1,15 @@ /** * Based on https://github.com/dwengovzw/Learning-Object-Repository/blob/main/app/processors/markdown/learing_object_markdown_renderer.js [sic!] */ -import PdfProcessor from "../pdf/pdf-processor.js"; -import AudioProcessor from "../audio/audio-processor.js"; -import ExternProcessor from "../extern/extern-processor.js"; -import InlineImageProcessor from "../image/inline-image-processor.js"; -import * as marked from "marked"; -import {getUrlStringForLearningObjectHTML, isValidHttpUrl} from "../../../../util/links"; -import {ProcessingError} from "../processing-error"; -import {LearningObjectIdentifier} from "../../../../interfaces/learning-content"; -import {Language} from "../../../../entities/content/language"; +import PdfProcessor from '../pdf/pdf-processor.js'; +import AudioProcessor from '../audio/audio-processor.js'; +import ExternProcessor from '../extern/extern-processor.js'; +import InlineImageProcessor from '../image/inline-image-processor.js'; +import * as marked from 'marked'; +import { getUrlStringForLearningObjectHTML, isValidHttpUrl } from '../../../../util/links'; +import { ProcessingError } from '../processing-error'; +import { LearningObjectIdentifier } from '../../../../interfaces/learning-content'; +import { Language } from '../../../../entities/content/language'; import Image = marked.Tokens.Image; import Heading = marked.Tokens.Heading; @@ -27,11 +27,11 @@ const prefixes = { }; function extractLearningObjectIdFromHref(href: string): LearningObjectIdentifier { - const [hruid, language, version] = href.split(/\/(.+)/, 2)[1].split("/"); + const [hruid, language, version] = href.split(/\/(.+)/, 2)[1].split('/'); return { hruid, language: language as Language, - version: parseInt(version) + version: parseInt(version), }; } @@ -41,39 +41,40 @@ function extractLearningObjectIdFromHref(href: string): LearningObjectIdentifier * - links to other learning objects, * - embeddings of other learning objects. */ - const dwengoMarkedRenderer: RendererObject = { +const dwengoMarkedRenderer: RendererObject = { heading(heading: Heading): string { const text = heading.text; const level = heading.depth; const escapedText = text.toLowerCase().replace(/[^\w]+/g, '-'); - return `\n` + - ` \n` + - ` \n` + - ` \n` + - ` ${text}\n` + - `\n` + return ( + `\n` + + ` \n` + + ` \n` + + ` \n` + + ` ${text}\n` + + `\n` + ); }, // When the syntax for a link is used => [text](href "title") // Render a custom link when the prefix for a learning object is used. link(link: Link): string { const href = link.href; - const title = link.title || ""; + const title = link.title || ''; const text = marked.parseInline(link.text); // There could for example be an image in the link. if (href.startsWith(prefixes.learningObject)) { // Link to learning-object const learningObjectId = extractLearningObjectIdFromHref(href); return `${text}`; - } - // Any other link - if (!isValidHttpUrl(href)) { - throw new ProcessingError("Link is not a valid HTTP URL!"); - } - // - return `${text}`; - + } + // Any other link + if (!isValidHttpUrl(href)) { + throw new ProcessingError('Link is not a valid HTTP URL!'); + } + // + return `${text}`; }, // When the syntax for an image is used => ![text](href "title") @@ -98,12 +99,11 @@ function extractLearningObjectIdFromHref(href: string): LearningObjectIdentifier // Embedded youtube video or notebook (or other extern content) const proc = new ExternProcessor(); return proc.render(href.split(/\/(.+)/, 2)[1]); - } - // Embedded image - const proc = new InlineImageProcessor(); - return proc.render(href) - + } + // Embedded image + const proc = new InlineImageProcessor(); + return proc.render(href); }, -} +}; export default dwengoMarkedRenderer; diff --git a/backend/src/services/learning-objects/processing/markdown/markdown-processor.ts b/backend/src/services/learning-objects/processing/markdown/markdown-processor.ts index 58824c13..5daeceec 100644 --- a/backend/src/services/learning-objects/processing/markdown/markdown-processor.ts +++ b/backend/src/services/learning-objects/processing/markdown/markdown-processor.ts @@ -2,12 +2,12 @@ * Based on https://github.com/dwengovzw/Learning-Object-Repository/blob/main/app/processors/markdown/markdown_processor.js */ -import {marked} from 'marked'; +import { marked } from 'marked'; import InlineImageProcessor from '../image/inline-image-processor.js'; -import {DwengoContentType} from "../content-type"; -import dwengoMarkedRenderer from "./dwengo-marked-renderer"; -import {StringProcessor} from "../string-processor"; -import {ProcessingError} from "../processing-error"; +import { DwengoContentType } from '../content-type'; +import dwengoMarkedRenderer from './dwengo-marked-renderer'; +import { StringProcessor } from '../string-processor'; +import { ProcessingError } from '../processing-error'; class MarkdownProcessor extends StringProcessor { constructor() { @@ -15,10 +15,10 @@ class MarkdownProcessor extends StringProcessor { } override renderFn(mdText: string) { - let html = ""; + let html = ''; try { - marked.use({renderer: dwengoMarkedRenderer}); - html = marked(mdText, {async: false}); + marked.use({ renderer: dwengoMarkedRenderer }); + html = marked(mdText, { async: false }); html = this.replaceLinks(html); // Replace html image links path } catch (e: any) { throw new ProcessingError(e.message); @@ -28,14 +28,10 @@ class MarkdownProcessor extends StringProcessor { replaceLinks(html: string) { const proc = new InlineImageProcessor(); - html = html.replace(//g, ( - match: string, - src: string, - alt: string, - altText: string, - title: string, - titleText: string - ) => proc.render(src)); + html = html.replace( + //g, + (match: string, src: string, alt: string, altText: string, title: string, titleText: string) => proc.render(src) + ); return html; } } diff --git a/backend/src/services/learning-objects/processing/pdf/pdf-processor.ts b/backend/src/services/learning-objects/processing/pdf/pdf-processor.ts index dcb08ba7..2ebed94e 100644 --- a/backend/src/services/learning-objects/processing/pdf/pdf-processor.ts +++ b/backend/src/services/learning-objects/processing/pdf/pdf-processor.ts @@ -5,10 +5,10 @@ */ import DOMPurify from 'isomorphic-dompurify'; -import {DwengoContentType} from "../content-type.js"; -import {isValidHttpUrl} from "../../../../util/links.js"; -import {ProcessingError} from "../processing-error.js"; -import {StringProcessor} from "../string-processor"; +import { DwengoContentType } from '../content-type.js'; +import { isValidHttpUrl } from '../../../../util/links.js'; +import { ProcessingError } from '../processing-error.js'; +import { StringProcessor } from '../string-processor'; class PdfProcessor extends StringProcessor { constructor() { @@ -20,9 +20,11 @@ class PdfProcessor extends StringProcessor { throw new ProcessingError(`PDF URL is invalid: ${pdfUrl}`); } - return DOMPurify.sanitize(` + return DOMPurify.sanitize( + ` - `, { ADD_TAGS: ["embed"] } + `, + { ADD_TAGS: ['embed'] } ); } } diff --git a/backend/src/services/learning-objects/processing/processing-service.ts b/backend/src/services/learning-objects/processing/processing-service.ts index c682de32..5bdbbd9c 100644 --- a/backend/src/services/learning-objects/processing/processing-service.ts +++ b/backend/src/services/learning-objects/processing/processing-service.ts @@ -2,20 +2,20 @@ * Based on https://github.com/dwengovzw/Learning-Object-Repository/blob/main/app/processors/processing_proxy.js */ -import BlockImageProcessor from "./image/block-image-processor.js"; -import InlineImageProcessor from "./image/inline-image-processor.js"; -import { MarkdownProcessor } from "./markdown/markdown-processor.js"; -import TextProcessor from "./text/text-processor.js"; -import AudioProcessor from "./audio/audio-processor.js"; -import PdfProcessor from "./pdf/pdf-processor.js"; -import ExternProcessor from "./extern/extern-processor.js"; -import GiftProcessor from "./gift/gift-processor.js"; -import {LearningObject} from "../../../entities/content/learning-object.entity"; -import Processor from "./processor"; -import {DwengoContentType} from "./content-type"; -import {LearningObjectIdentifier} from "../../../interfaces/learning-content"; -import {Language} from "../../../entities/content/language"; -import {replaceAsync} from "../../../util/async"; +import BlockImageProcessor from './image/block-image-processor.js'; +import InlineImageProcessor from './image/inline-image-processor.js'; +import { MarkdownProcessor } from './markdown/markdown-processor.js'; +import TextProcessor from './text/text-processor.js'; +import AudioProcessor from './audio/audio-processor.js'; +import PdfProcessor from './pdf/pdf-processor.js'; +import ExternProcessor from './extern/extern-processor.js'; +import GiftProcessor from './gift/gift-processor.js'; +import { LearningObject } from '../../../entities/content/learning-object.entity'; +import Processor from './processor'; +import { DwengoContentType } from './content-type'; +import { LearningObjectIdentifier } from '../../../interfaces/learning-content'; +import { Language } from '../../../entities/content/language'; +import { replaceAsync } from '../../../util/async'; const EMBEDDED_LEARNING_OBJECT_PLACEHOLDER = //g; const LEARNING_OBJECT_DOES_NOT_EXIST = "
"; @@ -32,12 +32,10 @@ class ProcessingService { new AudioProcessor(), new PdfProcessor(), new ExternProcessor(), - new GiftProcessor() + new GiftProcessor(), ]; - this.processors = new Map( - processors.map(processor => [processor.contentType, processor]) - ) + this.processors = new Map(processors.map((processor) => [processor.contentType, processor])); } /** @@ -65,7 +63,7 @@ class ProcessingService { const learningObject = await fetchEmbeddedLearningObjects({ hruid, language: language as Language, - version: parseInt(version) + version: parseInt(version), }); // If it does not exist, replace it by a placeholder. diff --git a/backend/src/services/learning-objects/processing/processor.ts b/backend/src/services/learning-objects/processing/processor.ts index 3e511cd9..85e11cee 100644 --- a/backend/src/services/learning-objects/processing/processor.ts +++ b/backend/src/services/learning-objects/processing/processor.ts @@ -1,6 +1,6 @@ -import {LearningObject} from "../../../entities/content/learning-object.entity"; -import {ProcessingError} from "./processing-error"; -import {DwengoContentType} from "./content-type"; +import { LearningObject } from '../../../entities/content/learning-object.entity'; +import { ProcessingError } from './processing-error'; +import { DwengoContentType } from './content-type'; /** * Abstract base class for all processors. diff --git a/backend/src/services/learning-objects/processing/string-processor.ts b/backend/src/services/learning-objects/processing/string-processor.ts index 2026fa93..df5e6ed3 100644 --- a/backend/src/services/learning-objects/processing/string-processor.ts +++ b/backend/src/services/learning-objects/processing/string-processor.ts @@ -1,5 +1,5 @@ -import Processor from "./processor"; -import {LearningObject} from "../../../entities/content/learning-object.entity"; +import Processor from './processor'; +import { LearningObject } from '../../../entities/content/learning-object.entity'; export abstract class StringProcessor extends Processor { /** @@ -14,6 +14,6 @@ export abstract class StringProcessor extends Processor { * @protected */ protected renderLearningObjectFn(toRender: LearningObject): string { - return this.render(toRender.content.toString("ascii")); + return this.render(toRender.content.toString('ascii')); } } diff --git a/backend/src/services/learning-objects/processing/text/text-processor.ts b/backend/src/services/learning-objects/processing/text/text-processor.ts index fb3922a7..6b4ca248 100644 --- a/backend/src/services/learning-objects/processing/text/text-processor.ts +++ b/backend/src/services/learning-objects/processing/text/text-processor.ts @@ -3,8 +3,8 @@ */ import DOMPurify from 'isomorphic-dompurify'; -import {DwengoContentType} from "../content-type.js"; -import {StringProcessor} from "../string-processor"; +import { DwengoContentType } from '../content-type.js'; +import { StringProcessor } from '../string-processor'; class TextProcessor extends StringProcessor { constructor() { diff --git a/backend/src/services/learning-paths/database-learning-path-provider.ts b/backend/src/services/learning-paths/database-learning-path-provider.ts index 60edb98b..3b3b49af 100644 --- a/backend/src/services/learning-paths/database-learning-path-provider.ts +++ b/backend/src/services/learning-paths/database-learning-path-provider.ts @@ -1,19 +1,11 @@ -import {LearningPathProvider} from "./learning-path-provider"; -import { - FilteredLearningObject, - LearningObjectNode, - LearningPath, - LearningPathResponse, - Transition -} from "../../interfaces/learning-content"; -import { - LearningPath as LearningPathEntity -} from "../../entities/content/learning-path.entity" -import {getLearningPathRepository} from "../../data/repositories"; -import {Language} from "../../entities/content/language"; -import learningObjectService from "../learning-objects/learning-object-service"; -import { LearningPathNode } from "../../entities/content/learning-path-node.entity"; -import {LearningPathTransition} from "../../entities/content/learning-path-transition.entity"; +import { LearningPathProvider } from './learning-path-provider'; +import { FilteredLearningObject, LearningObjectNode, LearningPath, LearningPathResponse, Transition } from '../../interfaces/learning-content'; +import { LearningPath as LearningPathEntity } from '../../entities/content/learning-path.entity'; +import { getLearningPathRepository } from '../../data/repositories'; +import { Language } from '../../entities/content/language'; +import learningObjectService from '../learning-objects/learning-object-service'; +import { LearningPathNode } from '../../entities/content/learning-path-node.entity'; +import { LearningPathTransition } from '../../entities/content/learning-path-transition.entity'; /** * Fetches the corresponding learning object for each of the nodes and creates a map that maps each node to its @@ -25,19 +17,19 @@ async function getLearningObjectsForNodes(nodes: LearningPathNode[]): Promise( await Promise.all( - nodes.map(node => - learningObjectService.getLearningObjectById({ - hruid: node.learningObjectHruid, - version: node.version, - language: node.language - }).then(learningObject => - <[LearningPathNode, FilteredLearningObject | null]>[node, learningObject] - ) + nodes.map((node) => + learningObjectService + .getLearningObjectById({ + hruid: node.learningObjectHruid, + version: node.version, + language: node.language, + }) + .then((learningObject) => <[LearningPathNode, FilteredLearningObject | null]>[node, learningObject]) ) ) ); - if (nullableNodesToLearningObjects.values().some(it => it === null)) { - throw new Error("At least one of the learning objects on this path could not be found.") + if (nullableNodesToLearningObjects.values().some((it) => it === null)) { + throw new Error('At least one of the learning objects on this path could not be found.'); } return nullableNodesToLearningObjects as Map; } @@ -46,16 +38,19 @@ async function getLearningObjectsForNodes(nodes: LearningPathNode[]): Promise { - const nodesToLearningObjects: Map = - await getLearningObjectsForNodes(learningPath.nodes); + const nodesToLearningObjects: Map = await getLearningObjectsForNodes(learningPath.nodes); - const targetAges = - nodesToLearningObjects.values().flatMap(it => it.targetAges || []).toArray(); + const targetAges = nodesToLearningObjects + .values() + .flatMap((it) => it.targetAges || []) + .toArray(); - const keywords = - nodesToLearningObjects.values().flatMap(it => it.keywords || []).toArray(); + const keywords = nodesToLearningObjects + .values() + .flatMap((it) => it.keywords || []) + .toArray(); - const image = learningPath.image ? learningPath.image.toString("base64") : undefined; + const image = learningPath.image ? learningPath.image.toString('base64') : undefined; return { _id: `${learningPath.hruid}/${learningPath.language}`, // For backwards compatibility with the original Dwengo API. @@ -71,8 +66,8 @@ async function convertLearningPath(learningPath: LearningPathEntity, order: numb keywords: keywords.join(' '), target_ages: targetAges, max_age: Math.max(...targetAges), - min_age: Math.min(...targetAges) - } + min_age: Math.min(...targetAges), + }; } /** @@ -80,24 +75,23 @@ async function convertLearningPath(learningPath: LearningPathEntity, order: numb * learning objects into a list of learning path nodes as they should be represented in the API. * @param nodesToLearningObjects */ -function convertNodes( - nodesToLearningObjects: Map -): LearningObjectNode[] { - return nodesToLearningObjects.entries().map((entry) => { - const [node, learningObject] = entry; - return { - _id: learningObject.uuid, - language: learningObject.language, - start_node: node.startNode, - created_at: node.createdAt.toISOString(), - updatedAt: node.updatedAt.toISOString(), - learningobject_hruid: node.learningObjectHruid, - version: learningObject.version, - transitions: node.transitions.map((trans, i) => - convertTransition(trans, i, nodesToLearningObjects) - ) - } - }).toArray(); +function convertNodes(nodesToLearningObjects: Map): LearningObjectNode[] { + return nodesToLearningObjects + .entries() + .map((entry) => { + const [node, learningObject] = entry; + return { + _id: learningObject.uuid, + language: learningObject.language, + start_node: node.startNode, + created_at: node.createdAt.toISOString(), + updatedAt: node.updatedAt.toISOString(), + learningobject_hruid: node.learningObjectHruid, + version: learningObject.version, + transitions: node.transitions.map((trans, i) => convertTransition(trans, i, nodesToLearningObjects)), + }; + }) + .toArray(); } /** @@ -115,17 +109,17 @@ function convertTransition( ): Transition { const nextNode = nodesToLearningObjects.get(transition.next); if (!nextNode) { - throw new Error(`Learning object ${transition.next.learningObjectHruid}/${transition.next.language}/${transition.next.version} not found!`) + throw new Error(`Learning object ${transition.next.learningObjectHruid}/${transition.next.language}/${transition.next.version} not found!`); } else { return { - _id: "" + index, // Retained for backwards compatibility. The index uniquely identifies the transition within the learning path. + _id: '' + index, // Retained for backwards compatibility. The index uniquely identifies the transition within the learning path. default: false, // We don't work with default transitions but retain this for backwards compatibility. next: { _id: nextNode._id + index, // Construct a unique ID for the transition for backwards compatibility. hruid: transition.next.learningObjectHruid, language: nextNode.language, - version: nextNode.version - } + version: nextNode.version, + }, }; } } @@ -140,19 +134,15 @@ const databaseLearningPathProvider: LearningPathProvider = { async fetchLearningPaths(hruids: string[], language: Language, source: string): Promise { const learningPathRepo = getLearningPathRepository(); - const learningPaths = await Promise.all( - hruids.map(hruid => learningPathRepo.findByHruidAndLanguage(hruid, language)) - ); + const learningPaths = await Promise.all(hruids.map((hruid) => learningPathRepo.findByHruidAndLanguage(hruid, language))); const filteredLearningPaths = await Promise.all( - learningPaths - .filter(learningPath => learningPath !== null) - .map((learningPath, index) => convertLearningPath(learningPath, index)) + learningPaths.filter((learningPath) => learningPath !== null).map((learningPath, index) => convertLearningPath(learningPath, index)) ); return { success: filteredLearningPaths.length > 0, data: await Promise.all(filteredLearningPaths), - source + source, }; }, @@ -163,12 +153,8 @@ const databaseLearningPathProvider: LearningPathProvider = { const learningPathRepo = getLearningPathRepository(); const searchResults = await learningPathRepo.findByQueryStringAndLanguage(query, language); - return await Promise.all( - searchResults.map((result, index) => - convertLearningPath(result, index) - ) - ); - } -} + return await Promise.all(searchResults.map((result, index) => convertLearningPath(result, index))); + }, +}; export default databaseLearningPathProvider; diff --git a/backend/src/services/learning-paths/dwengo-api-learning-path-provider.ts b/backend/src/services/learning-paths/dwengo-api-learning-path-provider.ts index ae6dff0a..037f7dd3 100644 --- a/backend/src/services/learning-paths/dwengo-api-learning-path-provider.ts +++ b/backend/src/services/learning-paths/dwengo-api-learning-path-provider.ts @@ -1,17 +1,10 @@ import { fetchWithLogging } from '../../util/apiHelper.js'; import { DWENGO_API_BASE } from '../../config.js'; -import { - LearningPath, - LearningPathResponse, -} from '../../interfaces/learning-content.js'; -import {LearningPathProvider} from "./learning-path-provider"; +import { LearningPath, LearningPathResponse } from '../../interfaces/learning-content.js'; +import { LearningPathProvider } from './learning-path-provider'; const dwengoApiLearningPathProvider: LearningPathProvider = { - async fetchLearningPaths( - hruids: string[], - language: string, - source: string - ): Promise { + async fetchLearningPaths(hruids: string[], language: string, source: string): Promise { if (hruids.length === 0) { return { success: false, @@ -24,11 +17,7 @@ const dwengoApiLearningPathProvider: LearningPathProvider = { const apiUrl = `${DWENGO_API_BASE}/learningPath/getPathsFromIdList`; const params = { pathIdList: JSON.stringify({ hruids }), language }; - const learningPaths = await fetchWithLogging( - apiUrl, - `Learning paths for ${source}`, - { params } - ); + const learningPaths = await fetchWithLogging(apiUrl, `Learning paths for ${source}`, { params }); if (!learningPaths || learningPaths.length === 0) { console.error(`⚠️ WARNING: No learning paths found for ${source}.`); @@ -46,20 +35,13 @@ const dwengoApiLearningPathProvider: LearningPathProvider = { data: learningPaths, }; }, - async searchLearningPaths( - query: string, - language: string - ): Promise { + async searchLearningPaths(query: string, language: string): Promise { const apiUrl = `${DWENGO_API_BASE}/learningPath/search`; const params = { all: query, language }; - const searchResults = await fetchWithLogging( - apiUrl, - `Search learning paths with query "${query}"`, - { params } - ); + const searchResults = await fetchWithLogging(apiUrl, `Search learning paths with query "${query}"`, { params }); return searchResults ?? []; - } + }, }; export default dwengoApiLearningPathProvider; diff --git a/backend/src/services/learning-paths/learning-path-personalizing-service.ts b/backend/src/services/learning-paths/learning-path-personalizing-service.ts index 6cd8f610..f204d742 100644 --- a/backend/src/services/learning-paths/learning-path-personalizing-service.ts +++ b/backend/src/services/learning-paths/learning-path-personalizing-service.ts @@ -1,21 +1,21 @@ -import {Student} from "../../entities/users/student.entity"; -import {getSubmissionRepository} from "../../data/repositories"; -import {Group} from "../../entities/assignments/group.entity"; -import {Submission} from "../../entities/assignments/submission.entity"; -import {LearningObjectIdentifier} from "../../entities/content/learning-object-identifier"; -import {LearningPathNode} from "../../entities/content/learning-path-node.entity"; -import {LearningPathTransition} from "../../entities/content/learning-path-transition.entity"; -import {JSONPath} from 'jsonpath-plus'; +import { Student } from '../../entities/users/student.entity'; +import { getSubmissionRepository } from '../../data/repositories'; +import { Group } from '../../entities/assignments/group.entity'; +import { Submission } from '../../entities/assignments/submission.entity'; +import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier'; +import { LearningPathNode } from '../../entities/content/learning-path-node.entity'; +import { LearningPathTransition } from '../../entities/content/learning-path-transition.entity'; +import { JSONPath } from 'jsonpath-plus'; /** * Returns the last submission for the learning object associated with the given node and for the student or group */ -async function getLastRelevantSubmission(node: LearningPathNode, pathFor: {student?: Student, group?: Group}): Promise { +async function getLastRelevantSubmission(node: LearningPathNode, pathFor: { student?: Student; group?: Group }): Promise { const submissionRepo = getSubmissionRepository(); const learningObjectId: LearningObjectIdentifier = { hruid: node.learningObjectHruid, language: node.language, - version: node.version + version: node.version, }; let lastSubmission: Submission | null; if (pathFor.group) { @@ -23,47 +23,46 @@ async function getLastRelevantSubmission(node: LearningPathNode, pathFor: {stude } else if (pathFor.student) { lastSubmission = await submissionRepo.findMostRecentSubmissionForStudent(learningObjectId, pathFor.student); } else { - throw new Error("The path must either be created for a certain group or for a certain student!"); + throw new Error('The path must either be created for a certain group or for a certain student!'); } return lastSubmission; } function transitionPossible(transition: LearningPathTransition, submitted: object | null): boolean { - if (transition.condition === "true" || !transition.condition) { + if (transition.condition === 'true' || !transition.condition) { return true; // If the transition is unconditional, we can go on. } if (submitted === null) { return false; // If the transition is not unconditional and there was no submission, the transition is not possible. } - return JSONPath({path: transition.condition, json: submitted}).length === 0; + return JSONPath({ path: transition.condition, json: submitted }).length === 0; } /** * Service to create individual trajectories from learning paths based on the submissions of the student or group. */ const learningPathPersonalizingService = { - async calculatePersonalizedTrajectory(nodes: LearningPathNode[], pathFor: {student?: Student, group?: Group}): Promise { + async calculatePersonalizedTrajectory(nodes: LearningPathNode[], pathFor: { student?: Student; group?: Group }): Promise { const trajectory: LearningPathNode[] = []; // Always start with the start node. - let currentNode = nodes.filter(it => it.startNode)[0]; + let currentNode = nodes.filter((it) => it.startNode)[0]; trajectory.push(currentNode); while (true) { // At every node, calculate all the possible next transitions. const lastSubmission = await getLastRelevantSubmission(currentNode, pathFor); const submitted = lastSubmission === null ? null : JSON.parse(lastSubmission.content); - const possibleTransitions = currentNode.transitions - .filter(it => transitionPossible(it, submitted)); + const possibleTransitions = currentNode.transitions.filter((it) => transitionPossible(it, submitted)); - if (possibleTransitions.length === 0) { // If there are none, the trajectory has ended. + if (possibleTransitions.length === 0) { + // If there are none, the trajectory has ended. return trajectory; - } // Otherwise, take the first possible transition. - currentNode = possibleTransitions[0].node; - trajectory.push(currentNode); - + } // Otherwise, take the first possible transition. + currentNode = possibleTransitions[0].node; + trajectory.push(currentNode); } - } + }, }; export default learningPathPersonalizingService; diff --git a/backend/src/services/learning-paths/learning-path-provider.ts b/backend/src/services/learning-paths/learning-path-provider.ts index f7cb1c12..baff35bf 100644 --- a/backend/src/services/learning-paths/learning-path-provider.ts +++ b/backend/src/services/learning-paths/learning-path-provider.ts @@ -1,5 +1,5 @@ -import {LearningPath, LearningPathResponse} from "../../interfaces/learning-content"; -import {Language} from "../../entities/content/language"; +import { LearningPath, LearningPathResponse } from '../../interfaces/learning-content'; +import { Language } from '../../entities/content/language'; /** * Generic interface for a service which provides access to learning paths from a data source. diff --git a/backend/src/services/learning-paths/learning-path-service.ts b/backend/src/services/learning-paths/learning-path-service.ts index a00b4633..23f0d9ba 100644 --- a/backend/src/services/learning-paths/learning-path-service.ts +++ b/backend/src/services/learning-paths/learning-path-service.ts @@ -1,14 +1,11 @@ -import { - LearningPath, - LearningPathResponse -} from "../../interfaces/learning-content"; -import dwengoApiLearningPathProvider from "./dwengo-api-learning-path-provider"; -import databaseLearningPathProvider from "./database-learning-path-provider"; -import {EnvVars, getEnvVar} from "../../util/envvars"; -import {Language} from "../../entities/content/language"; +import { LearningPath, LearningPathResponse } from '../../interfaces/learning-content'; +import dwengoApiLearningPathProvider from './dwengo-api-learning-path-provider'; +import databaseLearningPathProvider from './database-learning-path-provider'; +import { EnvVars, getEnvVar } from '../../util/envvars'; +import { Language } from '../../entities/content/language'; const userContentPrefix = getEnvVar(EnvVars.UserContentPrefix); -const allProviders = [dwengoApiLearningPathProvider, databaseLearningPathProvider] +const allProviders = [dwengoApiLearningPathProvider, databaseLearningPathProvider]; /** * Service providing access to data about learning paths from the appropriate data source (database or Dwengo-api) @@ -18,18 +15,16 @@ const learningPathService = { * Fetch the learning paths with the given hruids from the data source. */ async fetchLearningPaths(hruids: string[], language: Language, source: string): Promise { - const userContentHruids = hruids.filter(hruid => hruid.startsWith(userContentPrefix)); - const nonUserContentHruids = hruids.filter(hruid => !hruid.startsWith(userContentPrefix)); + const userContentHruids = hruids.filter((hruid) => hruid.startsWith(userContentPrefix)); + const nonUserContentHruids = hruids.filter((hruid) => !hruid.startsWith(userContentPrefix)); - const userContentLearningPaths = - await databaseLearningPathProvider.fetchLearningPaths(userContentHruids, language, source); - const nonUserContentLearningPaths - = await dwengoApiLearningPathProvider.fetchLearningPaths(nonUserContentHruids, language, source); + const userContentLearningPaths = await databaseLearningPathProvider.fetchLearningPaths(userContentHruids, language, source); + const nonUserContentLearningPaths = await dwengoApiLearningPathProvider.fetchLearningPaths(nonUserContentHruids, language, source); return { data: (userContentLearningPaths.data || []).concat(nonUserContentLearningPaths.data || []), source: source, - success: userContentLearningPaths.success || nonUserContentLearningPaths.success + success: userContentLearningPaths.success || nonUserContentLearningPaths.success, }; }, @@ -37,13 +32,9 @@ const learningPathService = { * Search learning paths in the data source using the given search string. */ async searchLearningPaths(query: string, language: Language): Promise { - const providerResponses = await Promise.all( - allProviders.map( - provider => provider.searchLearningPaths(query, language) - ) - ); + const providerResponses = await Promise.all(allProviders.map((provider) => provider.searchLearningPaths(query, language))); return providerResponses.flat(); - } -} + }, +}; export default learningPathService; diff --git a/backend/src/util/apiHelper.ts b/backend/src/util/apiHelper.ts index a7600541..fff7a6a1 100644 --- a/backend/src/util/apiHelper.ts +++ b/backend/src/util/apiHelper.ts @@ -17,9 +17,9 @@ export async function fetchWithLogging( url: string, description: string, options?: { - params?: Record, - query?: Record, - responseType?: "json" | "text", + params?: Record; + query?: Record; + responseType?: 'json' | 'text'; } ): Promise { try { diff --git a/backend/src/util/async.ts b/backend/src/util/async.ts index 874c0b8e..a5fc9b82 100644 --- a/backend/src/util/async.ts +++ b/backend/src/util/async.ts @@ -16,7 +16,7 @@ export async function replaceAsync(str: string, regex: RegExp, replacementFn: (m }); // Wait for the replacements to get loaded. Reverse them so when popping them, we work in a FIFO manner. - const replacements: string[] = (await Promise.all(promises)); + const replacements: string[] = await Promise.all(promises); // Second run through matches: Replace them by their previously computed replacements. return str.replace(regex, () => replacements.pop()!); diff --git a/backend/src/util/envvars.ts b/backend/src/util/envvars.ts index eed6dce7..115291af 100644 --- a/backend/src/util/envvars.ts +++ b/backend/src/util/envvars.ts @@ -15,9 +15,9 @@ export const EnvVars: { [key: string]: EnvVar } = { DbUsername: { key: DB_PREFIX + 'USERNAME', required: true }, DbPassword: { key: DB_PREFIX + 'PASSWORD', required: true }, DbUpdate: { key: DB_PREFIX + 'UPDATE', defaultValue: false }, - LearningContentRepoApiBaseUrl: { key: PREFIX + "LEARNING_CONTENT_REPO_API_BASE_URL", defaultValue: "https://dwengo.org/backend/api"}, - FallbackLanguage: { key: PREFIX + "FALLBACK_LANGUAGE", defaultValue: "nl" }, - UserContentPrefix: { key: DB_PREFIX + 'USER_CONTENT_PREFIX', defaultValue: "u_" }, + LearningContentRepoApiBaseUrl: { key: PREFIX + 'LEARNING_CONTENT_REPO_API_BASE_URL', defaultValue: 'https://dwengo.org/backend/api' }, + FallbackLanguage: { key: PREFIX + 'FALLBACK_LANGUAGE', defaultValue: 'nl' }, + UserContentPrefix: { key: DB_PREFIX + 'USER_CONTENT_PREFIX', defaultValue: 'u_' }, IdpStudentUrl: { key: STUDENT_IDP_PREFIX + 'URL', required: true }, IdpStudentClientId: { key: STUDENT_IDP_PREFIX + 'CLIENT_ID', required: true }, IdpStudentJwksEndpoint: { key: STUDENT_IDP_PREFIX + 'JWKS_ENDPOINT', required: true }, diff --git a/backend/src/util/links.ts b/backend/src/util/links.ts index 5deb21c2..73e27965 100644 --- a/backend/src/util/links.ts +++ b/backend/src/util/links.ts @@ -1,9 +1,9 @@ -import {LearningObjectIdentifier} from "../interfaces/learning-content"; +import { LearningObjectIdentifier } from '../interfaces/learning-content'; export function isValidHttpUrl(url: string): boolean { try { - const parsedUrl = new URL(url, "http://test.be"); - return parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:"; + const parsedUrl = new URL(url, 'http://test.be'); + return parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:'; } catch (e) { return false; } diff --git a/backend/tests/data/content/attachment-repository.test.ts b/backend/tests/data/content/attachment-repository.test.ts index e6c4e44a..b4ce9583 100644 --- a/backend/tests/data/content/attachment-repository.test.ts +++ b/backend/tests/data/content/attachment-repository.test.ts @@ -1,21 +1,21 @@ -import {beforeAll, describe, expect, it} from "vitest"; -import {setupTestApp} from "../../setup-tests"; -import {getAttachmentRepository, getLearningObjectRepository} from "../../../src/data/repositories"; -import {AttachmentRepository} from "../../../src/data/content/attachment-repository"; -import {LearningObjectRepository} from "../../../src/data/content/learning-object-repository"; -import example from "../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example"; -import {LearningObject} from "../../../src/entities/content/learning-object.entity"; -import {Attachment} from "../../../src/entities/content/attachment.entity"; -import {LearningObjectIdentifier} from "../../../src/entities/content/learning-object-identifier"; +import { beforeAll, describe, expect, it } from 'vitest'; +import { setupTestApp } from '../../setup-tests'; +import { getAttachmentRepository, getLearningObjectRepository } from '../../../src/data/repositories'; +import { AttachmentRepository } from '../../../src/data/content/attachment-repository'; +import { LearningObjectRepository } from '../../../src/data/content/learning-object-repository'; +import example from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example'; +import { LearningObject } from '../../../src/entities/content/learning-object.entity'; +import { Attachment } from '../../../src/entities/content/attachment.entity'; +import { LearningObjectIdentifier } from '../../../src/entities/content/learning-object-identifier'; -const NEWER_TEST_SUFFIX = "nEweR"; +const NEWER_TEST_SUFFIX = 'nEweR'; -function createTestLearningObjects(learningObjectRepo: LearningObjectRepository): {older: LearningObject, newer: LearningObject} { +function createTestLearningObjects(learningObjectRepo: LearningObjectRepository): { older: LearningObject; newer: LearningObject } { const olderExample = example.createLearningObject(); learningObjectRepo.save(olderExample); const newerExample = example.createLearningObject(); - newerExample.title = "Newer example"; + newerExample.title = 'Newer example'; newerExample.version = 100; return { @@ -24,9 +24,9 @@ function createTestLearningObjects(learningObjectRepo: LearningObjectRepository) }; } -describe("AttachmentRepository", () => { +describe('AttachmentRepository', () => { let attachmentRepo: AttachmentRepository; - let exampleLearningObjects: {older: LearningObject, newer: LearningObject}; + let exampleLearningObjects: { older: LearningObject; newer: LearningObject }; let attachmentsOlderLearningObject: Attachment[]; beforeAll(async () => { @@ -35,10 +35,8 @@ describe("AttachmentRepository", () => { exampleLearningObjects = createTestLearningObjects(getLearningObjectRepository()); }); - it("can add attachments to learning objects without throwing an error", () => { - attachmentsOlderLearningObject = Object - .values(example.createAttachment) - .map(fn => fn(exampleLearningObjects.older)); + it('can add attachments to learning objects without throwing an error', () => { + attachmentsOlderLearningObject = Object.values(example.createAttachment).map((fn) => fn(exampleLearningObjects.older)); for (const attachment of attachmentsOlderLearningObject) { attachmentRepo.save(attachment); @@ -46,7 +44,7 @@ describe("AttachmentRepository", () => { }); let attachmentOnlyNewer: Attachment; - it("allows us to add attachments with the same name to a different learning object without throwing an error", () => { + it('allows us to add attachments with the same name to a different learning object without throwing an error', () => { attachmentOnlyNewer = Object.values(example.createAttachment)[0](exampleLearningObjects.newer); attachmentOnlyNewer.content.write(NEWER_TEST_SUFFIX); @@ -54,29 +52,23 @@ describe("AttachmentRepository", () => { }); let olderLearningObjectId: LearningObjectIdentifier; - it("returns the correct attachment when queried by learningObjectId and attachment name", async () => { + it('returns the correct attachment when queried by learningObjectId and attachment name', async () => { olderLearningObjectId = { hruid: exampleLearningObjects.older.hruid, language: exampleLearningObjects.older.language, - version: exampleLearningObjects.older.version + version: exampleLearningObjects.older.version, }; - const result = await attachmentRepo.findByLearningObjectIdAndName( - olderLearningObjectId, - attachmentsOlderLearningObject[0].name - ); + const result = await attachmentRepo.findByLearningObjectIdAndName(olderLearningObjectId, attachmentsOlderLearningObject[0].name); expect(result).toBe(attachmentsOlderLearningObject[0]); }); - it("returns null when queried by learningObjectId and non-existing attachment name", async () => { - const result = await attachmentRepo.findByLearningObjectIdAndName( - olderLearningObjectId, - "non-existing name" - ); + it('returns null when queried by learningObjectId and non-existing attachment name', async () => { + const result = await attachmentRepo.findByLearningObjectIdAndName(olderLearningObjectId, 'non-existing name'); expect(result).toBe(null); }); - it("returns the newer version of the attachment when only queried by hruid, language and attachment name (but not version)", async () => { + it('returns the newer version of the attachment when only queried by hruid, language and attachment name (but not version)', async () => { const result = await attachmentRepo.findByMostRecentVersionOfLearningObjectAndName( exampleLearningObjects.older.hruid, exampleLearningObjects.older.language, diff --git a/backend/tests/data/content/learning-object-repository.test.ts b/backend/tests/data/content/learning-object-repository.test.ts index bcca4c83..48c7494f 100644 --- a/backend/tests/data/content/learning-object-repository.test.ts +++ b/backend/tests/data/content/learning-object-repository.test.ts @@ -1,12 +1,12 @@ -import {beforeAll, describe, it, expect} from "vitest"; -import {LearningObjectRepository} from "../../../src/data/content/learning-object-repository"; -import {setupTestApp} from "../../setup-tests"; -import {getLearningObjectRepository} from "../../../src/data/repositories"; -import example from "../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.js" -import {LearningObject} from "../../../src/entities/content/learning-object.entity"; -import {expectToBeCorrectEntity} from "../../test-utils/expectations"; +import { beforeAll, describe, it, expect } from 'vitest'; +import { LearningObjectRepository } from '../../../src/data/content/learning-object-repository'; +import { setupTestApp } from '../../setup-tests'; +import { getLearningObjectRepository } from '../../../src/data/repositories'; +import example from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.js'; +import { LearningObject } from '../../../src/entities/content/learning-object.entity'; +import { expectToBeCorrectEntity } from '../../test-utils/expectations'; -describe("LearningObjectRepository", () => { +describe('LearningObjectRepository', () => { let learningObjectRepository: LearningObjectRepository; let exampleLearningObject: LearningObject; @@ -16,55 +16,57 @@ describe("LearningObjectRepository", () => { learningObjectRepository = getLearningObjectRepository(); }); - it("should be able to add a learning object to it without an error", async () => { + it('should be able to add a learning object to it without an error', async () => { exampleLearningObject = example.createLearningObject(); await learningObjectRepository.insert(exampleLearningObject); }); - it("should return the learning object when queried by id", async () => { + it('should return the learning object when queried by id', async () => { const result = await learningObjectRepository.findByIdentifier({ hruid: exampleLearningObject.hruid, language: exampleLearningObject.language, - version: exampleLearningObject.version + version: exampleLearningObject.version, }); expect(result).toBeInstanceOf(LearningObject); - expectToBeCorrectEntity({ - name: "actual", - entity: result! - }, { - name: "expected", - entity: exampleLearningObject - }); + expectToBeCorrectEntity( + { + name: 'actual', + entity: result!, + }, + { + name: 'expected', + entity: exampleLearningObject, + } + ); }); - it("should return null when non-existing version is queried", async () => { + it('should return null when non-existing version is queried', async () => { const result = await learningObjectRepository.findByIdentifier({ hruid: exampleLearningObject.hruid, language: exampleLearningObject.language, - version: 100 + version: 100, }); expect(result).toBe(null); }); let newerExample: LearningObject; - it("should allow a learning object with the same id except a different version to be added", async () => { + it('should allow a learning object with the same id except a different version to be added', async () => { newerExample = example.createLearningObject(); newerExample.version = 10; - newerExample.title += " (nieuw)"; + newerExample.title += ' (nieuw)'; await learningObjectRepository.save(newerExample); }); - it("should return the newest version of the learning object when queried by only hruid and language", async () => { + it('should return the newest version of the learning object when queried by only hruid and language', async () => { const result = await learningObjectRepository.findLatestByHruidAndLanguage(newerExample.hruid, newerExample.language); expect(result).toBeInstanceOf(LearningObject); expect(result?.version).toBe(10); - expect(result?.title).toContain("(nieuw)"); + expect(result?.title).toContain('(nieuw)'); }); - it("should return null when queried by non-existing hruid or language", async () => { - const result = await learningObjectRepository.findLatestByHruidAndLanguage("something_that_does_not_exist", exampleLearningObject.language); + it('should return null when queried by non-existing hruid or language', async () => { + const result = await learningObjectRepository.findLatestByHruidAndLanguage('something_that_does_not_exist', exampleLearningObject.language); expect(result).toBe(null); }); - }); diff --git a/backend/tests/data/content/learning-path-repository.test.ts b/backend/tests/data/content/learning-path-repository.test.ts index 5298d3c4..0b8b6a90 100644 --- a/backend/tests/data/content/learning-path-repository.test.ts +++ b/backend/tests/data/content/learning-path-repository.test.ts @@ -1,24 +1,24 @@ -import {beforeAll, describe, expect, it} from "vitest"; -import {setupTestApp} from "../../setup-tests"; -import {getLearningPathRepository} from "../../../src/data/repositories"; -import {LearningPathRepository} from "../../../src/data/content/learning-path-repository"; -import example from "../../test-assets/learning-paths/pn-werking-example"; -import {LearningPath} from "../../../src/entities/content/learning-path.entity"; -import {expectToBeCorrectEntity} from "../../test-utils/expectations"; -import {Language} from "../../../src/entities/content/language"; +import { beforeAll, describe, expect, it } from 'vitest'; +import { setupTestApp } from '../../setup-tests'; +import { getLearningPathRepository } from '../../../src/data/repositories'; +import { LearningPathRepository } from '../../../src/data/content/learning-path-repository'; +import example from '../../test-assets/learning-paths/pn-werking-example'; +import { LearningPath } from '../../../src/entities/content/learning-path.entity'; +import { expectToBeCorrectEntity } from '../../test-utils/expectations'; +import { Language } from '../../../src/entities/content/language'; function expectToHaveFoundPrecisely(expected: LearningPath, result: LearningPath[]): void { - expect(result).toHaveProperty("length"); + expect(result).toHaveProperty('length'); expect(result.length).toBe(1); expectToBeCorrectEntity({ entity: result[0]! }, { entity: expected }); } function expectToHaveFoundNothing(result: LearningPath[]): void { - expect(result).toHaveProperty("length"); + expect(result).toHaveProperty('length'); expect(result.length).toBe(0); } -describe("LearningPathRepository", () => { +describe('LearningPathRepository', () => { let learningPathRepo: LearningPathRepository; beforeAll(async () => { @@ -28,51 +28,39 @@ describe("LearningPathRepository", () => { let examplePath: LearningPath; - it("should be able to add a learning path without throwing an error", async () => { + it('should be able to add a learning path without throwing an error', async () => { examplePath = example.createLearningPath(); await learningPathRepo.insert(examplePath); }); - it("should return the added path when it is queried by hruid and language", async () => { + it('should return the added path when it is queried by hruid and language', async () => { const result = await learningPathRepo.findByHruidAndLanguage(examplePath.hruid, examplePath.language); expect(result).toBeInstanceOf(LearningPath); expectToBeCorrectEntity({ entity: result! }, { entity: examplePath }); }); - it("should return null to a query on a non-existing hruid or language", async () => { - const result = await learningPathRepo.findByHruidAndLanguage("not_existing_hruid", examplePath.language); + it('should return null to a query on a non-existing hruid or language', async () => { + const result = await learningPathRepo.findByHruidAndLanguage('not_existing_hruid', examplePath.language); expect(result).toBe(null); }); - it("should return the learning path when we search for a search term occurring in its title", async () => { - const result = await learningPathRepo.findByQueryStringAndLanguage( - examplePath.title.slice(4, 9), - examplePath.language - ); + it('should return the learning path when we search for a search term occurring in its title', async () => { + const result = await learningPathRepo.findByQueryStringAndLanguage(examplePath.title.slice(4, 9), examplePath.language); expectToHaveFoundPrecisely(examplePath, result); }); - it("should return the learning path when we search for a search term occurring in its description", async () => { - const result = await learningPathRepo.findByQueryStringAndLanguage( - examplePath.description.slice(8, 15), - examplePath.language - ); + it('should return the learning path when we search for a search term occurring in its description', async () => { + const result = await learningPathRepo.findByQueryStringAndLanguage(examplePath.description.slice(8, 15), examplePath.language); expectToHaveFoundPrecisely(examplePath, result); }); - it("should return null when we search for something not occurring in its title or description", async () => { - const result = await learningPathRepo.findByQueryStringAndLanguage( - "something not occurring in the path", - examplePath.language - ); + it('should return null when we search for something not occurring in its title or description', async () => { + const result = await learningPathRepo.findByQueryStringAndLanguage('something not occurring in the path', examplePath.language); expectToHaveFoundNothing(result); }); - it("should return null when we search for something occurring in its title, but another language", async () => { - const result = await learningPathRepo.findByQueryStringAndLanguage( - examplePath.description.slice(1, 3), - Language.Kalaallisut - ); + it('should return null when we search for something occurring in its title, but another language', async () => { + const result = await learningPathRepo.findByQueryStringAndLanguage(examplePath.description.slice(1, 3), Language.Kalaallisut); expectToHaveFoundNothing(result); }); }); diff --git a/backend/tests/services/learning-objects/database-learning-object-provider.test.ts b/backend/tests/services/learning-objects/database-learning-object-provider.test.ts index e3960f64..a37704f0 100644 --- a/backend/tests/services/learning-objects/database-learning-object-provider.test.ts +++ b/backend/tests/services/learning-objects/database-learning-object-provider.test.ts @@ -1,15 +1,13 @@ -import {beforeAll, describe, expect, it} from "vitest"; -import {setupTestApp} from "../../setup-tests"; -import {getLearningObjectRepository} from "../../../src/data/repositories"; -import example from "../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example"; -import {LearningObject} from "../../../src/entities/content/learning-object.entity"; -import databaseLearningObjectProvider from "../../../src/services/learning-objects/database-learning-object-provider"; -import { - createExampleLearningObjectWithAttachments -} from "../../test-assets/learning-objects/create-example-learning-object-with-attachments"; -import {expectToBeCorrectFilteredLearningObject} from "../../test-utils/expectations"; -import {FilteredLearningObject} from "../../../src/interfaces/learning-content"; -import {Language} from "../../../src/entities/content/language"; +import { beforeAll, describe, expect, it } from 'vitest'; +import { setupTestApp } from '../../setup-tests'; +import { getLearningObjectRepository } from '../../../src/data/repositories'; +import example from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example'; +import { LearningObject } from '../../../src/entities/content/learning-object.entity'; +import databaseLearningObjectProvider from '../../../src/services/learning-objects/database-learning-object-provider'; +import { createExampleLearningObjectWithAttachments } from '../../test-assets/learning-objects/create-example-learning-object-with-attachments'; +import { expectToBeCorrectFilteredLearningObject } from '../../test-utils/expectations'; +import { FilteredLearningObject } from '../../../src/interfaces/learning-content'; +import { Language } from '../../../src/entities/content/language'; async function initExampleData(): Promise { const learningObjectRepo = getLearningObjectRepository(); @@ -18,39 +16,39 @@ async function initExampleData(): Promise { return exampleLearningObject; } -describe("DatabaseLearningObjectProvider", () => { +describe('DatabaseLearningObjectProvider', () => { let exampleLearningObject: LearningObject; beforeAll(async () => { await setupTestApp(); exampleLearningObject = await initExampleData(); }); - describe("getLearningObjectById", () => { - it("should return the learning object when it is queried by its id", async () => { + describe('getLearningObjectById', () => { + it('should return the learning object when it is queried by its id', async () => { const result: FilteredLearningObject | null = await databaseLearningObjectProvider.getLearningObjectById(exampleLearningObject); expect(result).toBeTruthy(); expectToBeCorrectFilteredLearningObject(result!, exampleLearningObject); }); - it("should return the learning object when it is queried by only hruid and language (but not version)", async () => { + it('should return the learning object when it is queried by only hruid and language (but not version)', async () => { const result: FilteredLearningObject | null = await databaseLearningObjectProvider.getLearningObjectById({ hruid: exampleLearningObject.hruid, - language: exampleLearningObject.language + language: exampleLearningObject.language, }); expect(result).toBeTruthy(); expectToBeCorrectFilteredLearningObject(result!, exampleLearningObject); }); - it("should return null when queried with an id that does not exist", async () => { + it('should return null when queried with an id that does not exist', async () => { const result: FilteredLearningObject | null = await databaseLearningObjectProvider.getLearningObjectById({ - hruid: "non_existing_hruid", - language: Language.Dutch + hruid: 'non_existing_hruid', + language: Language.Dutch, }); expect(result).toBeNull(); }); }); - describe("getLearningObjectHTML", () => { - it("should return the correct rendering of the learning object", async () => { + describe('getLearningObjectHTML', () => { + it('should return the correct rendering of the learning object', async () => { const result = await databaseLearningObjectProvider.getLearningObjectHTML(exampleLearningObject); expect(result).toEqual(example.getHTMLRendering()); }); diff --git a/backend/tests/services/learning-objects/learning-object-service.test.ts b/backend/tests/services/learning-objects/learning-object-service.test.ts index 2a68d797..26f03595 100644 --- a/backend/tests/services/learning-objects/learning-object-service.test.ts +++ b/backend/tests/services/learning-objects/learning-object-service.test.ts @@ -1,30 +1,30 @@ -import {beforeAll, describe, expect, it} from "vitest"; -import {setupTestApp} from "../../setup-tests"; -import {LearningObject} from "../../../src/entities/content/learning-object.entity"; -import {getLearningObjectRepository} from "../../../src/data/repositories"; -import learningObjectExample from "../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example"; -import learningObjectService from "../../../src/services/learning-objects/learning-object-service"; -import {LearningObjectIdentifier} from "../../../src/interfaces/learning-content"; -import {Language} from "../../../src/entities/content/language"; -import {EnvVars, getEnvVar} from "../../../src/util/envvars"; +import { beforeAll, describe, expect, it } from 'vitest'; +import { setupTestApp } from '../../setup-tests'; +import { LearningObject } from '../../../src/entities/content/learning-object.entity'; +import { getLearningObjectRepository } from '../../../src/data/repositories'; +import learningObjectExample from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example'; +import learningObjectService from '../../../src/services/learning-objects/learning-object-service'; +import { LearningObjectIdentifier } from '../../../src/interfaces/learning-content'; +import { Language } from '../../../src/entities/content/language'; +import { EnvVars, getEnvVar } from '../../../src/util/envvars'; -const TEST_LEARNING_OBJECT_TITLE = "Test title"; -const EXPECTED_DWENGO_LEARNING_OBJECT_TITLE = "Werken met notebooks"; +const TEST_LEARNING_OBJECT_TITLE = 'Test title'; +const EXPECTED_DWENGO_LEARNING_OBJECT_TITLE = 'Werken met notebooks'; const DWENGO_TEST_LEARNING_OBJECT_ID: LearningObjectIdentifier = { - hruid: "pn_werkingnotebooks", + hruid: 'pn_werkingnotebooks', language: Language.Dutch, - version: 3 + version: 3, }; async function initExampleData(): Promise { const learningObjectRepo = getLearningObjectRepository(); const learningObject = learningObjectExample.createLearningObject(); - learningObject.title = TEST_LEARNING_OBJECT_TITLE + learningObject.title = TEST_LEARNING_OBJECT_TITLE; await learningObjectRepo.save(learningObject); return learningObject; } -describe("LearningObjectService", () => { +describe('LearningObjectService', () => { let exampleLearningObject: LearningObject; beforeAll(async () => { @@ -32,47 +32,50 @@ describe("LearningObjectService", () => { exampleLearningObject = await initExampleData(); }); - describe("getLearningObjectById", () => { - it("returns the learning object from the Dwengo API if it does not have the user content prefix", async () => { + describe('getLearningObjectById', () => { + it('returns the learning object from the Dwengo API if it does not have the user content prefix', async () => { const result = await learningObjectService.getLearningObjectById(DWENGO_TEST_LEARNING_OBJECT_ID); expect(result).not.toBeNull(); expect(result?.title).toBe(EXPECTED_DWENGO_LEARNING_OBJECT_TITLE); }); - it("returns the learning object from the database if it does have the user content prefix", async () => { + it('returns the learning object from the database if it does have the user content prefix', async () => { const result = await learningObjectService.getLearningObjectById(exampleLearningObject); expect(result).not.toBeNull(); expect(result?.title).toBe(exampleLearningObject.title); }); - it("returns null if the hruid does not have the user content prefix and does not exist in the Dwengo repo", async () => { + it('returns null if the hruid does not have the user content prefix and does not exist in the Dwengo repo', async () => { const result = await learningObjectService.getLearningObjectById({ - hruid: "non-existing", - language: Language.Dutch + hruid: 'non-existing', + language: Language.Dutch, }); expect(result).toBeNull(); }); }); - describe("getLearningObjectHTML", () => { - it("returns the expected HTML when queried with the identifier of a learning object saved in the database", async () => { + describe('getLearningObjectHTML', () => { + it('returns the expected HTML when queried with the identifier of a learning object saved in the database', async () => { const result = await learningObjectService.getLearningObjectHTML(exampleLearningObject); expect(result).not.toBeNull(); expect(result).toEqual(learningObjectExample.getHTMLRendering()); }); - it("returns the same HTML as the Dwengo API when queried with the identifier of a learning object that does " + - "not start with the user content prefix", async () => { - const result = await learningObjectService.getLearningObjectHTML(DWENGO_TEST_LEARNING_OBJECT_ID); - expect(result).not.toBeNull(); + it( + 'returns the same HTML as the Dwengo API when queried with the identifier of a learning object that does ' + + 'not start with the user content prefix', + async () => { + const result = await learningObjectService.getLearningObjectHTML(DWENGO_TEST_LEARNING_OBJECT_ID); + expect(result).not.toBeNull(); - const htmlFromDwengoApi = await fetch( - getEnvVar(EnvVars.LearningContentRepoApiBaseUrl) - + `/learningObject/getRaw?hruid=${DWENGO_TEST_LEARNING_OBJECT_ID.hruid}&language=${DWENGO_TEST_LEARNING_OBJECT_ID.language}&version=${DWENGO_TEST_LEARNING_OBJECT_ID.version}` - ).then(it => it.text()); - expect(result).toEqual(htmlFromDwengoApi); - }); - it("returns null when queried with a non-existing identifier", async () => { + const htmlFromDwengoApi = await fetch( + getEnvVar(EnvVars.LearningContentRepoApiBaseUrl) + + `/learningObject/getRaw?hruid=${DWENGO_TEST_LEARNING_OBJECT_ID.hruid}&language=${DWENGO_TEST_LEARNING_OBJECT_ID.language}&version=${DWENGO_TEST_LEARNING_OBJECT_ID.version}` + ).then((it) => it.text()); + expect(result).toEqual(htmlFromDwengoApi); + } + ); + it('returns null when queried with a non-existing identifier', async () => { const result = await learningObjectService.getLearningObjectHTML({ - hruid: "non_existing_hruid", - language: Language.Dutch + hruid: 'non_existing_hruid', + language: Language.Dutch, }); expect(result).toBeNull(); }); diff --git a/backend/tests/services/learning-objects/processing/processing-service.test.ts b/backend/tests/services/learning-objects/processing/processing-service.test.ts index f0107162..27714317 100644 --- a/backend/tests/services/learning-objects/processing/processing-service.test.ts +++ b/backend/tests/services/learning-objects/processing/processing-service.test.ts @@ -1,23 +1,23 @@ -import {describe, expect, it} from "vitest"; -import mdExample from "../../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example"; -import multipleChoiceExample from "../../../test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example"; -import essayExample from "../../../test-assets/learning-objects/test-essay/test-essay-example"; -import processingService from "../../../../src/services/learning-objects/processing/processing-service"; +import { describe, expect, it } from 'vitest'; +import mdExample from '../../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example'; +import multipleChoiceExample from '../../../test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example'; +import essayExample from '../../../test-assets/learning-objects/test-essay/test-essay-example'; +import processingService from '../../../../src/services/learning-objects/processing/processing-service'; -describe("ProcessingService", () => { - it("renders a markdown learning object correctly", async () => { +describe('ProcessingService', () => { + it('renders a markdown learning object correctly', async () => { const markdownLearningObject = mdExample.createLearningObject(); const result = await processingService.render(markdownLearningObject); expect(result).toEqual(mdExample.getHTMLRendering()); }); - it("renders a multiple choice question correctly", async () => { + it('renders a multiple choice question correctly', async () => { const multipleChoiceLearningObject = multipleChoiceExample.createLearningObject(); const result = await processingService.render(multipleChoiceLearningObject); expect(result).toEqual(multipleChoiceExample.getHTMLRendering()); }); - it("renders an essay question correctly", async () => { + it('renders an essay question correctly', async () => { const essayLearningObject = essayExample.createLearningObject(); const result = await processingService.render(essayLearningObject); expect(result).toEqual(essayExample.getHTMLRendering()); diff --git a/backend/tests/services/learning-path/database-learning-path-provider.test.ts b/backend/tests/services/learning-path/database-learning-path-provider.test.ts index 8dd3d07b..df49ae3b 100644 --- a/backend/tests/services/learning-path/database-learning-path-provider.test.ts +++ b/backend/tests/services/learning-path/database-learning-path-provider.test.ts @@ -1,17 +1,17 @@ -import {beforeAll, describe, expect, it} from "vitest"; -import {LearningObject} from "../../../src/entities/content/learning-object.entity"; -import {setupTestApp} from "../../setup-tests"; -import {LearningPath} from "../../../src/entities/content/learning-path.entity"; -import {getLearningObjectRepository, getLearningPathRepository} from "../../../src/data/repositories"; -import learningObjectExample from "../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example"; -import learningPathExample from "../../test-assets/learning-paths/pn-werking-example" -import databaseLearningPathProvider from "../../../src/services/learning-paths/database-learning-path-provider"; -import {expectToBeCorrectLearningPath} from "../../test-utils/expectations"; -import {LearningObjectRepository} from "../../../src/data/content/learning-object-repository"; -import learningObjectService from "../../../src/services/learning-objects/learning-object-service"; -import {Language} from "../../../src/entities/content/language"; +import { beforeAll, describe, expect, it } from 'vitest'; +import { LearningObject } from '../../../src/entities/content/learning-object.entity'; +import { setupTestApp } from '../../setup-tests'; +import { LearningPath } from '../../../src/entities/content/learning-path.entity'; +import { getLearningObjectRepository, getLearningPathRepository } from '../../../src/data/repositories'; +import learningObjectExample from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example'; +import learningPathExample from '../../test-assets/learning-paths/pn-werking-example'; +import databaseLearningPathProvider from '../../../src/services/learning-paths/database-learning-path-provider'; +import { expectToBeCorrectLearningPath } from '../../test-utils/expectations'; +import { LearningObjectRepository } from '../../../src/data/content/learning-object-repository'; +import learningObjectService from '../../../src/services/learning-objects/learning-object-service'; +import { Language } from '../../../src/entities/content/language'; -async function initExampleData(): Promise<{ learningObject: LearningObject, learningPath: LearningPath }> { +async function initExampleData(): Promise<{ learningObject: LearningObject; learningPath: LearningPath }> { const learningObjectRepo = getLearningObjectRepository(); const learningPathRepo = getLearningPathRepository(); const learningObject = learningObjectExample.createLearningObject(); @@ -21,9 +21,9 @@ async function initExampleData(): Promise<{ learningObject: LearningObject, lear return { learningObject, learningPath }; } -describe("DatabaseLearningPathProvider", () => { +describe('DatabaseLearningPathProvider', () => { let learningObjectRepo: LearningObjectRepository; - let example: {learningObject: LearningObject, learningPath: LearningPath}; + let example: { learningObject: LearningObject; learningPath: LearningPath }; beforeAll(async () => { await setupTestApp(); @@ -31,40 +31,43 @@ describe("DatabaseLearningPathProvider", () => { learningObjectRepo = getLearningObjectRepository(); }); - describe("fetchLearningPaths", () => { - it("returns the learning path correctly", async () => { + describe('fetchLearningPaths', () => { + it('returns the learning path correctly', async () => { const result = await databaseLearningPathProvider.fetchLearningPaths( [example.learningPath.hruid], example.learningPath.language, - "the source" + 'the source' ); expect(result.success).toBe(true); expect(result.data?.length).toBe(1); - const learningObjectsOnPath = (await Promise.all( - example.learningPath.nodes.map(node => - learningObjectService.getLearningObjectById({ - hruid: node.learningObjectHruid, - version: node.version, - language: node.language - })) - )).filter(it => it !== null); + const learningObjectsOnPath = ( + await Promise.all( + example.learningPath.nodes.map((node) => + learningObjectService.getLearningObjectById({ + hruid: node.learningObjectHruid, + version: node.version, + language: node.language, + }) + ) + ) + ).filter((it) => it !== null); - expectToBeCorrectLearningPath(result.data![0], example.learningPath, learningObjectsOnPath) + expectToBeCorrectLearningPath(result.data![0], example.learningPath, learningObjectsOnPath); }); - it("returns a non-successful response if a non-existing learning path is queried", async () => { + it('returns a non-successful response if a non-existing learning path is queried', async () => { const result = await databaseLearningPathProvider.fetchLearningPaths( [example.learningPath.hruid], Language.Abkhazian, // Wrong language - "the source" + 'the source' ); expect(result.success).toBe(false); }); }); - describe("searchLearningPaths", () => { - it("returns the correct learning path when queried with a substring of its title", async () => { + describe('searchLearningPaths', () => { + it('returns the correct learning path when queried with a substring of its title', async () => { const result = await databaseLearningPathProvider.searchLearningPaths( example.learningPath.title.substring(2, 6), example.learningPath.language @@ -73,7 +76,7 @@ describe("DatabaseLearningPathProvider", () => { expect(result[0].title).toBe(example.learningPath.title); expect(result[0].description).toBe(example.learningPath.description); }); - it("returns the correct learning path when queried with a substring of the description", async () => { + it('returns the correct learning path when queried with a substring of the description', async () => { const result = await databaseLearningPathProvider.searchLearningPaths( example.learningPath.description.substring(5, 12), example.learningPath.language @@ -82,9 +85,9 @@ describe("DatabaseLearningPathProvider", () => { expect(result[0].title).toBe(example.learningPath.title); expect(result[0].description).toBe(example.learningPath.description); }); - it("returns an empty result when queried with a text which is not a substring of the title or the description of a learning path", async () => { + it('returns an empty result when queried with a text which is not a substring of the title or the description of a learning path', async () => { const result = await databaseLearningPathProvider.searchLearningPaths( - "substring which does not occur in the title or the description of a learning object", + 'substring which does not occur in the title or the description of a learning object', example.learningPath.language ); expect(result.length).toBe(0); diff --git a/backend/tests/services/learning-path/learning-path-service.test.ts b/backend/tests/services/learning-path/learning-path-service.test.ts index b64d527a..cceb19be 100644 --- a/backend/tests/services/learning-path/learning-path-service.test.ts +++ b/backend/tests/services/learning-path/learning-path-service.test.ts @@ -1,14 +1,14 @@ -import {beforeAll, describe, expect, it} from "vitest"; -import {setupTestApp} from "../../setup-tests"; -import {LearningObject} from "../../../src/entities/content/learning-object.entity"; -import {LearningPath} from "../../../src/entities/content/learning-path.entity"; -import {getLearningObjectRepository, getLearningPathRepository} from "../../../src/data/repositories"; -import learningObjectExample from "../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example"; -import learningPathExample from "../../test-assets/learning-paths/pn-werking-example"; -import {Language} from "../../../src/entities/content/language"; -import learningPathService from "../../../src/services/learning-paths/learning-path-service"; +import { beforeAll, describe, expect, it } from 'vitest'; +import { setupTestApp } from '../../setup-tests'; +import { LearningObject } from '../../../src/entities/content/learning-object.entity'; +import { LearningPath } from '../../../src/entities/content/learning-path.entity'; +import { getLearningObjectRepository, getLearningPathRepository } from '../../../src/data/repositories'; +import learningObjectExample from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example'; +import learningPathExample from '../../test-assets/learning-paths/pn-werking-example'; +import { Language } from '../../../src/entities/content/language'; +import learningPathService from '../../../src/services/learning-paths/learning-path-service'; -async function initExampleData(): Promise<{ learningObject: LearningObject, learningPath: LearningPath }> { +async function initExampleData(): Promise<{ learningObject: LearningObject; learningPath: LearningPath }> { const learningObjectRepo = getLearningObjectRepository(); const learningPathRepo = getLearningPathRepository(); const learningObject = learningObjectExample.createLearningObject(); @@ -18,88 +18,63 @@ async function initExampleData(): Promise<{ learningObject: LearningObject, lear return { learningObject, learningPath }; } -const TEST_DWENGO_LEARNING_PATH_HRUID = "pn_werking"; -const TEST_DWENGO_LEARNING_PATH_TITLE = "Werken met notebooks"; -const TEST_DWENGO_EXCLUSIVE_LEARNING_PATH_SEARCH_QUERY = "Microscopie"; -const TEST_SEARCH_QUERY_EXPECTING_NO_MATCHES = "su$m8f9usf89ud { - let example: { learningObject: LearningObject, learningPath: LearningPath }; +describe('LearningPathService', () => { + let example: { learningObject: LearningObject; learningPath: LearningPath }; beforeAll(async () => { await setupTestApp(); example = await initExampleData(); }); - describe("fetchLearningPaths", () => { - it("should return learning paths both from the database and from the Dwengo API", async () => { + describe('fetchLearningPaths', () => { + it('should return learning paths both from the database and from the Dwengo API', async () => { const result = await learningPathService.fetchLearningPaths( [example.learningPath.hruid, TEST_DWENGO_LEARNING_PATH_HRUID], example.learningPath.language, - "the source" + 'the source' ); expect(result.success).toBeTruthy(); - expect(result.data?.filter(it => it.hruid == TEST_DWENGO_LEARNING_PATH_HRUID).length).not.toBe(0); - expect(result.data?.filter(it => it.hruid == example.learningPath.hruid).length).not.toBe(0); - expect(result.data?.filter(it => it.hruid == TEST_DWENGO_LEARNING_PATH_HRUID)[0].title) - .toEqual(TEST_DWENGO_LEARNING_PATH_TITLE); - expect(result.data?.filter(it => it.hruid == example.learningPath.hruid)[0].title) - .toEqual(example.learningPath.title); + expect(result.data?.filter((it) => it.hruid == TEST_DWENGO_LEARNING_PATH_HRUID).length).not.toBe(0); + expect(result.data?.filter((it) => it.hruid == example.learningPath.hruid).length).not.toBe(0); + expect(result.data?.filter((it) => it.hruid == TEST_DWENGO_LEARNING_PATH_HRUID)[0].title).toEqual(TEST_DWENGO_LEARNING_PATH_TITLE); + expect(result.data?.filter((it) => it.hruid == example.learningPath.hruid)[0].title).toEqual(example.learningPath.title); }); - it("should include both the learning objects from the Dwengo API and learning objects from the database in its response", async () => { - const result = await learningPathService.fetchLearningPaths( - [example.learningPath.hruid], - example.learningPath.language, - "the source" - ); + it('should include both the learning objects from the Dwengo API and learning objects from the database in its response', async () => { + const result = await learningPathService.fetchLearningPaths([example.learningPath.hruid], example.learningPath.language, 'the source'); expect(result.success).toBeTruthy(); expect(result.data?.length).toBe(1); // Should include all the nodes, even those pointing to foreign learning objects. - expect( - [...result.data![0].nodes.map(it => it.learningobject_hruid)].sort() - ).toEqual( - example.learningPath.nodes.map(it => it.learningObjectHruid).sort() + expect([...result.data![0].nodes.map((it) => it.learningobject_hruid)].sort()).toEqual( + example.learningPath.nodes.map((it) => it.learningObjectHruid).sort() ); }); }); - describe("searchLearningPath", () => { - it("should include both the learning paths from the Dwengo API and those from the database in its response", async () => { + describe('searchLearningPath', () => { + it('should include both the learning paths from the Dwengo API and those from the database in its response', async () => { // This matches the learning object in the database, but definitely also some learning objects in the Dwengo API. - const result = await learningPathService.searchLearningPaths( - example.learningPath.title.substring(2, 3), - example.learningPath.language - ); + const result = await learningPathService.searchLearningPaths(example.learningPath.title.substring(2, 3), example.learningPath.language); // Should find the one from the database - expect( - result.filter(it => - it.hruid === example.learningPath.hruid && it.title === example.learningPath.title - ).length - ).toBe(1); + expect(result.filter((it) => it.hruid === example.learningPath.hruid && it.title === example.learningPath.title).length).toBe(1); // But should not only find that one. expect(result.length).not.toBeLessThan(2); }); - it("should still return results from the Dwengo API even though there are no matches in the database", async () => { - const result = await learningPathService.searchLearningPaths( - TEST_DWENGO_EXCLUSIVE_LEARNING_PATH_SEARCH_QUERY, - Language.Dutch - ); + it('should still return results from the Dwengo API even though there are no matches in the database', async () => { + const result = await learningPathService.searchLearningPaths(TEST_DWENGO_EXCLUSIVE_LEARNING_PATH_SEARCH_QUERY, Language.Dutch); // Should find something... expect(result.length).not.toBe(0); // But not the example learning path. - expect( - result.filter(it => - it.hruid === example.learningPath.hruid && it.title === example.learningPath.title - ).length - ).toBe(0); + expect(result.filter((it) => it.hruid === example.learningPath.hruid && it.title === example.learningPath.title).length).toBe(0); }); - it("should return an empty list if neither the Dwengo API nor the database contains matches", async () => { - const result = await learningPathService.searchLearningPaths( - TEST_SEARCH_QUERY_EXPECTING_NO_MATCHES, - Language.Dutch - ); + it('should return an empty list if neither the Dwengo API nor the database contains matches', async () => { + const result = await learningPathService.searchLearningPaths(TEST_SEARCH_QUERY_EXPECTING_NO_MATCHES, Language.Dutch); expect(result.length).toBe(0); }); }); diff --git a/backend/tests/test-assets/learning-objects/create-example-learning-object-with-attachments.ts b/backend/tests/test-assets/learning-objects/create-example-learning-object-with-attachments.ts index c0177fbf..9bd0b4c3 100644 --- a/backend/tests/test-assets/learning-objects/create-example-learning-object-with-attachments.ts +++ b/backend/tests/test-assets/learning-objects/create-example-learning-object-with-attachments.ts @@ -1,5 +1,5 @@ -import {LearningObjectExample} from "./learning-object-example"; -import {LearningObject} from "../../../src/entities/content/learning-object.entity"; +import { LearningObjectExample } from './learning-object-example'; +import { LearningObject } from '../../../src/entities/content/learning-object.entity'; export function createExampleLearningObjectWithAttachments(example: LearningObjectExample): LearningObject { const learningObject = example.createLearningObject(); diff --git a/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts b/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts index dfc15a7a..5b773d09 100644 --- a/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts +++ b/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts @@ -1,8 +1,8 @@ -import {LearningObjectExample} from "../learning-object-example"; -import {LearningObject} from "../../../../src/entities/content/learning-object.entity"; -import {Language} from "../../../../src/entities/content/language"; -import {loadTestAsset} from "../../../test-utils/load-test-asset"; -import {DwengoContentType} from "../../../../src/services/learning-objects/processing/content-type"; +import { LearningObjectExample } from '../learning-object-example'; +import { LearningObject } from '../../../../src/entities/content/learning-object.entity'; +import { Language } from '../../../../src/entities/content/language'; +import { loadTestAsset } from '../../../test-utils/load-test-asset'; +import { DwengoContentType } from '../../../../src/services/learning-objects/processing/content-type'; /** * Create a dummy learning object to be used in tests where multiple learning objects are needed (for example for use @@ -16,12 +16,12 @@ export function dummyLearningObject(hruid: string, language: Language, title: st learningObject.language = language; learningObject.version = 1; learningObject.title = title; - learningObject.description = "Just a dummy learning object for testing purposes"; + learningObject.description = 'Just a dummy learning object for testing purposes'; learningObject.contentType = DwengoContentType.TEXT_PLAIN; - learningObject.content = Buffer.from("Dummy content"); + learningObject.content = Buffer.from('Dummy content'); return learningObject; }, createAttachment: {}, - getHTMLRendering: () => loadTestAsset("learning-objects/dummy/rendering.html").toString() - } + getHTMLRendering: () => loadTestAsset('learning-objects/dummy/rendering.html').toString(), + }; } diff --git a/backend/tests/test-assets/learning-objects/learning-object-example.d.ts b/backend/tests/test-assets/learning-objects/learning-object-example.d.ts index 90808fe9..1d4009f8 100644 --- a/backend/tests/test-assets/learning-objects/learning-object-example.d.ts +++ b/backend/tests/test-assets/learning-objects/learning-object-example.d.ts @@ -1,8 +1,8 @@ -import {LearningObject} from "../../../src/entities/content/learning-object.entity"; -import {Attachment} from "../../../src/entities/content/attachment.entity"; +import { LearningObject } from '../../../src/entities/content/learning-object.entity'; +import { Attachment } from '../../../src/entities/content/attachment.entity'; type LearningObjectExample = { - createLearningObject: () => LearningObject, - createAttachment: {[key: string]: (owner: LearningObject) => Attachment}, - getHTMLRendering: () => string + createLearningObject: () => LearningObject; + createAttachment: { [key: string]: (owner: LearningObject) => Attachment }; + getHTMLRendering: () => string; }; diff --git a/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/content.md b/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/content.md index 0161bbd0..f469e46c 100644 --- a/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/content.md +++ b/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/content.md @@ -4,7 +4,7 @@ Het lesmateriaal van 'Python in wiskunde en STEM' wordt aangeboden in de vorm va _Nieuwe begrippen_ worden aangebracht via tekstuele uitleg, video en afbeeldingen. -Er zijn uitgewerkte *voorbeelden* met daarnaast ook kleine en grote *opdrachten*. In deze opdrachten zal je aangereikte code kunnen uitvoeren, maar ook zelf code opstellen. +Er zijn uitgewerkte _voorbeelden_ met daarnaast ook kleine en grote _opdrachten_. In deze opdrachten zal je aangereikte code kunnen uitvoeren, maar ook zelf code opstellen. De code die in de notebooks gebruikt wordt, is Python versie 3. We kozen voor Python omdat dit een heel toegankelijke programmeertaal is, die vaak ook intuïtief is. Python is bovendien bezig aan een opmars en wordt gebruikt door bedrijven, zoals Google, NASA, Netflix, Uber, AstraZeneca, Barco, Instagram en YouTube. @@ -12,14 +12,15 @@ Python is bovendien bezig aan een opmars en wordt gebruikt door bedrijven, zoals We kozen voor notebooks omdat daar enkele belangrijke voordelen aan verbonden zijn: leerkrachten moeten geen geavanceerde installaties doen om de notebooks te gebruiken, leerkrachten kunnen verschillende soorten van lesinhouden aanbieden via één platform, de notebooks zijn interactief, leerlingen bouwen de oplossing van een probleem stap voor stap op in de notebook waardoor dat proces zichtbaar is voor de leerkracht ([Jeroen Van der Hooft, 2023](https://libstore.ugent.be/fulltxt/RUG01/003/151/437/RUG01-003151437_2023_0001_AC.pdf)). --- -Klik je op onderstaande knop 'Open notebooks', dan word je doorgestuurd naar een andere website waar jouw persoonlijke notebooks ingeladen worden. (Dit kan even duren.) + +Klik je op onderstaande knop 'Open notebooks', dan word je doorgestuurd naar een andere website waar jouw persoonlijke notebooks ingeladen worden. (Dit kan even duren.) Links op het scherm vind je er twee bestanden met extensie _.ipynb_. Dit zijn de twee notebooks waarin je resp. een overzicht krijgt van de opbouw en mogelijkheden en hoe je er mee aan de slag kan. Dubbelklik op de bestandsnaam om een notebook te openen. -Je ziet er ook een map *images* met de afbeeldingen die in de notebooks getoond worden. +Je ziet er ook een map _images_ met de afbeeldingen die in de notebooks getoond worden. In deze eerste twee notebooks leer je hoe de notebooks zijn opgevat en hoe je ermee aan de slag kan. Na het doorlopen van beide notebooks heb je een goed idee van hoe onze Python notebooks zijn opgevat. -[![](Knop.png "Knop")](https://kiks.ilabt.imec.be/hub/tmplogin?id=0101 "Notebooks Werking") +[![](Knop.png 'Knop')](https://kiks.ilabt.imec.be/hub/tmplogin?id=0101 'Notebooks Werking') diff --git a/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.ts b/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.ts index 9a7f340c..5bca09a6 100644 --- a/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.ts +++ b/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.ts @@ -1,30 +1,30 @@ -import {LearningObjectExample} from "../learning-object-example"; -import {Language} from "../../../../src/entities/content/language"; -import {DwengoContentType} from "../../../../src/services/learning-objects/processing/content-type"; -import {loadTestAsset} from "../../../test-utils/load-test-asset"; -import {EducationalGoal, LearningObject, ReturnValue} from "../../../../src/entities/content/learning-object.entity"; -import {Attachment} from "../../../../src/entities/content/attachment.entity"; -import {EnvVars, getEnvVar} from "../../../../src/util/envvars"; +import { LearningObjectExample } from '../learning-object-example'; +import { Language } from '../../../../src/entities/content/language'; +import { DwengoContentType } from '../../../../src/services/learning-objects/processing/content-type'; +import { loadTestAsset } from '../../../test-utils/load-test-asset'; +import { EducationalGoal, LearningObject, ReturnValue } from '../../../../src/entities/content/learning-object.entity'; +import { Attachment } from '../../../../src/entities/content/attachment.entity'; +import { EnvVars, getEnvVar } from '../../../../src/util/envvars'; -const ASSETS_PREFIX = "learning-objects/pn-werkingnotebooks/"; +const ASSETS_PREFIX = 'learning-objects/pn-werkingnotebooks/'; const example: LearningObjectExample = { - createLearningObject: ()=> { + createLearningObject: () => { const learningObject = new LearningObject(); learningObject.hruid = `${getEnvVar(EnvVars.UserContentPrefix)}pn_werkingnotebooks`; learningObject.version = 3; learningObject.language = Language.Dutch; - learningObject.title = "Werken met notebooks"; - learningObject.description = "Leren werken met notebooks"; - learningObject.keywords = ["Python", "KIKS", "Wiskunde", "STEM", "AI"] + learningObject.title = 'Werken met notebooks'; + learningObject.description = 'Leren werken met notebooks'; + learningObject.keywords = ['Python', 'KIKS', 'Wiskunde', 'STEM', 'AI']; const educationalGoal1 = new EducationalGoal(); - educationalGoal1.source = "Source"; - educationalGoal1.id = "id"; + educationalGoal1.source = 'Source'; + educationalGoal1.id = 'id'; const educationalGoal2 = new EducationalGoal(); - educationalGoal2.source = "Source2"; - educationalGoal2.id = "id2"; + educationalGoal2.source = 'Source2'; + educationalGoal2.id = 'id2'; learningObject.educationalGoals = [educationalGoal1, educationalGoal2]; learningObject.admins = []; @@ -33,40 +33,40 @@ const example: LearningObjectExample = { learningObject.skosConcepts = [ 'http://ilearn.ilabt.imec.be/vocab/curr1/s-vaktaal', 'http://ilearn.ilabt.imec.be/vocab/curr1/s-digitale-media-en-toepassingen', - 'http://ilearn.ilabt.imec.be/vocab/curr1/s-computers-en-systemen' + 'http://ilearn.ilabt.imec.be/vocab/curr1/s-computers-en-systemen', ]; - learningObject.copyright = "dwengo"; - learningObject.license = "dwengo"; + learningObject.copyright = 'dwengo'; + learningObject.license = 'dwengo'; learningObject.estimatedTime = 10; const returnValue = new ReturnValue(); - returnValue.callbackUrl = "callback_url_example"; + returnValue.callbackUrl = 'callback_url_example'; returnValue.callbackSchema = '{"att": "test", "att2": "test2"}'; learningObject.returnValue = returnValue; learningObject.available = true; learningObject.content = loadTestAsset(`${ASSETS_PREFIX}/content.md`); - return learningObject + return learningObject; }, createAttachment: { dwengoLogo: (learningObject) => { const att = new Attachment(); att.learningObject = learningObject; - att.name = "dwengo.png"; - att.mimeType = "image/png"; - att.content = loadTestAsset(`${ASSETS_PREFIX}/dwengo.png`) + att.name = 'dwengo.png'; + att.mimeType = 'image/png'; + att.content = loadTestAsset(`${ASSETS_PREFIX}/dwengo.png`); return att; }, knop: (learningObject) => { const att = new Attachment(); att.learningObject = learningObject; - att.name = "Knop.png"; - att.mimeType = "image/png"; - att.content = loadTestAsset(`${ASSETS_PREFIX}/Knop.png`) + att.name = 'Knop.png'; + att.mimeType = 'image/png'; + att.content = loadTestAsset(`${ASSETS_PREFIX}/Knop.png`); return att; - } + }, }, - getHTMLRendering: () => loadTestAsset(`${ASSETS_PREFIX}/rendering.html`).toString() -} + getHTMLRendering: () => loadTestAsset(`${ASSETS_PREFIX}/rendering.html`).toString(), +}; export default example; diff --git a/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/rendering.html b/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/rendering.html index d197ebd4..ab9bd34e 100644 --- a/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/rendering.html +++ b/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/rendering.html @@ -4,17 +4,44 @@ Werken met notebooks -

Het lesmateriaal van 'Python in wiskunde en STEM' wordt aangeboden in de vorm van interactieve notebooks. Notebooks zijn digitale documenten die zowel uitvoerbare code bevatten als tekst, afbeeldingen, video, hyperlinks ...

+

+ Het lesmateriaal van 'Python in wiskunde en STEM' wordt aangeboden in de vorm van interactieve notebooks. Notebooks zijn digitale documenten die zowel uitvoerbare code bevatten als tekst, afbeeldingen, video, hyperlinks ... +

Nieuwe begrippen worden aangebracht via tekstuele uitleg, video en afbeeldingen.

-

Er zijn uitgewerkte voorbeelden met daarnaast ook kleine en grote opdrachten. In deze opdrachten zal je aangereikte code kunnen uitvoeren, maar ook zelf code opstellen.

-

De code die in de notebooks gebruikt wordt, is Python versie 3. We kozen voor Python omdat dit een heel toegankelijke programmeertaal is, die vaak ook intuC/tief is. -Python is bovendien bezig aan een opmars en wordt gebruikt door bedrijven, zoals Google, NASA, Netflix, Uber, AstraZeneca, Barco, Instagram en YouTube.

-

We kozen voor notebooks omdat daar enkele belangrijke voordelen aan verbonden zijn: leerkrachten moeten geen geavanceerde installaties doen om de notebooks te gebruiken, leerkrachten kunnen verschillende soorten van lesinhouden aanbieden via C)C)n platform, de notebooks zijn interactief, leerlingen bouwen de oplossing van een probleem stap voor stap op in de notebook waardoor dat proces zichtbaar is voor de leerkracht (Jeroen Van der Hooft, 2023).

-
-

Klik je op onderstaande knop 'Open notebooks', dan word je doorgestuurd naar een andere website waar jouw persoonlijke notebooks ingeladen worden. (Dit kan even duren.)

-

Links op het scherm vind je er twee bestanden met extensie .ipynb. -Dit zijn de twee notebooks waarin je resp. een overzicht krijgt van de opbouw en mogelijkheden en hoe je er mee aan de slag kan. Dubbelklik op de bestandsnaam om een notebook te openen.

+

+ Er zijn uitgewerkte voorbeelden met daarnaast ook kleine en grote opdrachten. In deze opdrachten zal je aangereikte code kunnen + uitvoeren, maar ook zelf code opstellen. +

+

+ De code die in de notebooks gebruikt wordt, is Python versie 3. We kozen voor Python omdat dit een heel toegankelijke programmeertaal is, die vaak + ook intuC/tief is. Python is bovendien bezig aan een opmars en wordt gebruikt door bedrijven, zoals Google, NASA, Netflix, Uber, AstraZeneca, + Barco, Instagram en YouTube. +

+

+ We kozen voor notebooks omdat daar enkele belangrijke voordelen aan verbonden zijn: leerkrachten moeten geen geavanceerde installaties doen om de + notebooks te gebruiken, leerkrachten kunnen verschillende soorten van lesinhouden aanbieden via C)C)n platform, de notebooks zijn interactief, + leerlingen bouwen de oplossing van een probleem stap voor stap op in de notebook waardoor dat proces zichtbaar is voor de leerkracht (Jeroen Van der Hooft, 2023). +

+
+

+ Klik je op onderstaande knop 'Open notebooks', dan word je doorgestuurd naar een andere website waar jouw persoonlijke notebooks ingeladen + worden. (Dit kan even duren.) +

+

+ Links op het scherm vind je er twee bestanden met extensie .ipynb. Dit zijn de twee notebooks waarin je resp. een overzicht krijgt van de + opbouw en mogelijkheden en hoe je er mee aan de slag kan. Dubbelklik op de bestandsnaam om een notebook te openen. +

Je ziet er ook een map images met de afbeeldingen die in de notebooks getoond worden.

-

In deze eerste twee notebooks leer je hoe de notebooks zijn opgevat en hoe je ermee aan de slag kan. -Na het doorlopen van beide notebooks heb je een goed idee van hoe onze Python notebooks zijn opgevat.

-

+

+ In deze eerste twee notebooks leer je hoe de notebooks zijn opgevat en hoe je ermee aan de slag kan. Na het doorlopen van beide notebooks heb je + een goed idee van hoe onze Python notebooks zijn opgevat. +

+

+ +

diff --git a/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts b/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts index 08a818f7..7a2f54d9 100644 --- a/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts +++ b/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts @@ -1,9 +1,9 @@ -import {LearningObjectExample} from "../learning-object-example"; -import {LearningObject} from "../../../../src/entities/content/learning-object.entity"; -import {loadTestAsset} from "../../../test-utils/load-test-asset"; -import {EnvVars, getEnvVar} from "../../../../src/util/envvars"; -import {Language} from "../../../../src/entities/content/language"; -import {DwengoContentType} from "../../../../src/services/learning-objects/processing/content-type"; +import { LearningObjectExample } from '../learning-object-example'; +import { LearningObject } from '../../../../src/entities/content/learning-object.entity'; +import { loadTestAsset } from '../../../test-utils/load-test-asset'; +import { EnvVars, getEnvVar } from '../../../../src/util/envvars'; +import { Language } from '../../../../src/entities/content/language'; +import { DwengoContentType } from '../../../../src/services/learning-objects/processing/content-type'; const example: LearningObjectExample = { createLearningObject: () => { @@ -11,14 +11,14 @@ const example: LearningObjectExample = { learningObject.hruid = `${getEnvVar(EnvVars.UserContentPrefix)}test_essay`; learningObject.language = Language.English; learningObject.version = 1; - learningObject.title = "Essay question for testing"; - learningObject.description = "This essay question was only created for testing purposes."; + learningObject.title = 'Essay question for testing'; + learningObject.description = 'This essay question was only created for testing purposes.'; learningObject.contentType = DwengoContentType.GIFT; - learningObject.content = loadTestAsset("learning-objects/test-essay/content.txt"); + learningObject.content = loadTestAsset('learning-objects/test-essay/content.txt'); return learningObject; }, createAttachment: {}, - getHTMLRendering: () => loadTestAsset("learning-objects/test-essay/rendering.html").toString() + getHTMLRendering: () => loadTestAsset('learning-objects/test-essay/rendering.html').toString(), }; export default example; diff --git a/backend/tests/test-assets/learning-objects/test-multiple-choice/rendering.html b/backend/tests/test-assets/learning-objects/test-multiple-choice/rendering.html index c1829f24..513a29a5 100644 --- a/backend/tests/test-assets/learning-objects/test-multiple-choice/rendering.html +++ b/backend/tests/test-assets/learning-objects/test-multiple-choice/rendering.html @@ -3,11 +3,11 @@

MC basic

Are you following along well with the class?

- +
- +
diff --git a/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts b/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts index 6abc56dd..52b6adbe 100644 --- a/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts +++ b/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts @@ -1,9 +1,9 @@ -import {LearningObjectExample} from "../learning-object-example"; -import {LearningObject} from "../../../../src/entities/content/learning-object.entity"; -import {loadTestAsset} from "../../../test-utils/load-test-asset"; -import {EnvVars, getEnvVar} from "../../../../src/util/envvars"; -import {Language} from "../../../../src/entities/content/language"; -import {DwengoContentType} from "../../../../src/services/learning-objects/processing/content-type"; +import { LearningObjectExample } from '../learning-object-example'; +import { LearningObject } from '../../../../src/entities/content/learning-object.entity'; +import { loadTestAsset } from '../../../test-utils/load-test-asset'; +import { EnvVars, getEnvVar } from '../../../../src/util/envvars'; +import { Language } from '../../../../src/entities/content/language'; +import { DwengoContentType } from '../../../../src/services/learning-objects/processing/content-type'; const example: LearningObjectExample = { createLearningObject: () => { @@ -11,14 +11,14 @@ const example: LearningObjectExample = { learningObject.hruid = `${getEnvVar(EnvVars.UserContentPrefix)}test_multiple_choice`; learningObject.language = Language.English; learningObject.version = 1; - learningObject.title = "Multiple choice question for testing"; - learningObject.description = "This multiple choice question was only created for testing purposes."; + learningObject.title = 'Multiple choice question for testing'; + learningObject.description = 'This multiple choice question was only created for testing purposes.'; learningObject.contentType = DwengoContentType.GIFT; - learningObject.content = loadTestAsset("learning-objects/test-multiple-choice/content.txt"); + learningObject.content = loadTestAsset('learning-objects/test-multiple-choice/content.txt'); return learningObject; }, createAttachment: {}, - getHTMLRendering: () => loadTestAsset("learning-objects/test-multiple-choice/rendering.html").toString() + getHTMLRendering: () => loadTestAsset('learning-objects/test-multiple-choice/rendering.html').toString(), }; export default example; diff --git a/backend/tests/test-assets/learning-paths/learning-path-example.d.ts b/backend/tests/test-assets/learning-paths/learning-path-example.d.ts index 47d0221f..9df3ba48 100644 --- a/backend/tests/test-assets/learning-paths/learning-path-example.d.ts +++ b/backend/tests/test-assets/learning-paths/learning-path-example.d.ts @@ -1,3 +1,3 @@ type LearningPathExample = { - createLearningPath: () => LearningPath + createLearningPath: () => LearningPath; }; diff --git a/backend/tests/test-assets/learning-paths/learning-path-utils.ts b/backend/tests/test-assets/learning-paths/learning-path-utils.ts index 0a09145f..c567de66 100644 --- a/backend/tests/test-assets/learning-paths/learning-path-utils.ts +++ b/backend/tests/test-assets/learning-paths/learning-path-utils.ts @@ -1,13 +1,13 @@ -import {Language} from "../../../src/entities/content/language"; -import {LearningPathTransition} from "../../../src/entities/content/learning-path-transition.entity"; -import {LearningPathNode} from "../../../src/entities/content/learning-path-node.entity"; -import {LearningPath} from "../../../src/entities/content/learning-path.entity"; +import { Language } from '../../../src/entities/content/language'; +import { LearningPathTransition } from '../../../src/entities/content/learning-path-transition.entity'; +import { LearningPathNode } from '../../../src/entities/content/learning-path-node.entity'; +import { LearningPath } from '../../../src/entities/content/learning-path.entity'; export function createLearningPathTransition(node: LearningPathNode, transitionNumber: number, condition: string | null, to: LearningPathNode) { const trans = new LearningPathTransition(); trans.node = node; trans.transitionNumber = transitionNumber; - trans.condition = condition || "true"; + trans.condition = condition || 'true'; trans.next = to; return trans; } diff --git a/backend/tests/test-assets/learning-paths/pn-werking-example.ts b/backend/tests/test-assets/learning-paths/pn-werking-example.ts index 40a07587..810b4da5 100644 --- a/backend/tests/test-assets/learning-paths/pn-werking-example.ts +++ b/backend/tests/test-assets/learning-paths/pn-werking-example.ts @@ -1,17 +1,17 @@ -import {LearningPath} from "../../../src/entities/content/learning-path.entity"; -import {Language} from "../../../src/entities/content/language"; -import {EnvVars, getEnvVar} from "../../../src/util/envvars"; -import {createLearningPathNode, createLearningPathTransition} from "./learning-path-utils"; -import {LearningPathNode} from "../../../src/entities/content/learning-path-node.entity"; +import { LearningPath } from '../../../src/entities/content/learning-path.entity'; +import { Language } from '../../../src/entities/content/language'; +import { EnvVars, getEnvVar } from '../../../src/util/envvars'; +import { createLearningPathNode, createLearningPathTransition } from './learning-path-utils'; +import { LearningPathNode } from '../../../src/entities/content/learning-path-node.entity'; function createNodes(learningPath: LearningPath): LearningPathNode[] { const nodes = [ - createLearningPathNode(learningPath, 0, "u_pn_werkingnotebooks", 3, Language.Dutch, true), - createLearningPathNode(learningPath, 1, "pn_werkingnotebooks2", 3, Language.Dutch, false), - createLearningPathNode(learningPath, 2, "pn_werkingnotebooks3", 3, Language.Dutch, false), + createLearningPathNode(learningPath, 0, 'u_pn_werkingnotebooks', 3, Language.Dutch, true), + createLearningPathNode(learningPath, 1, 'pn_werkingnotebooks2', 3, Language.Dutch, false), + createLearningPathNode(learningPath, 2, 'pn_werkingnotebooks3', 3, Language.Dutch, false), ]; - nodes[0].transitions.push(createLearningPathTransition(nodes[0], 0, "true", nodes[1])); - nodes[1].transitions.push(createLearningPathTransition(nodes[1], 0, "true", nodes[2])); + nodes[0].transitions.push(createLearningPathTransition(nodes[0], 0, 'true', nodes[1])); + nodes[1].transitions.push(createLearningPathTransition(nodes[1], 0, 'true', nodes[2])); return nodes; } @@ -20,11 +20,11 @@ const example: LearningPathExample = { const path = new LearningPath(); path.language = Language.Dutch; path.hruid = `${getEnvVar(EnvVars.UserContentPrefix)}pn_werking`; - path.title = "Werken met notebooks"; - path.description = "Een korte inleiding tot Python notebooks. Hoe ga je gemakkelijk en efficiënt met de notebooks aan de slag?"; + path.title = 'Werken met notebooks'; + path.description = 'Een korte inleiding tot Python notebooks. Hoe ga je gemakkelijk en efficiënt met de notebooks aan de slag?'; path.nodes = createNodes(path); return path; - } -} + }, +}; export default example; diff --git a/backend/tests/test-assets/learning-paths/test-conditions-example.ts b/backend/tests/test-assets/learning-paths/test-conditions-example.ts index 000bb732..b6cf3e9d 100644 --- a/backend/tests/test-assets/learning-paths/test-conditions-example.ts +++ b/backend/tests/test-assets/learning-paths/test-conditions-example.ts @@ -1,23 +1,27 @@ -import {LearningPath} from "../../../src/entities/content/learning-path.entity"; -import {Language} from "../../../src/entities/content/language"; -import testMultipleChoiceExample from "../learning-objects/test-multiple-choice/test-multiple-choice-example"; -import {dummyLearningObject} from "../learning-objects/dummy/dummy-learning-object-example"; -import {createLearningPathNode, createLearningPathTransition} from "./learning-path-utils"; +import { LearningPath } from '../../../src/entities/content/learning-path.entity'; +import { Language } from '../../../src/entities/content/language'; +import testMultipleChoiceExample from '../learning-objects/test-multiple-choice/test-multiple-choice-example'; +import { dummyLearningObject } from '../learning-objects/dummy/dummy-learning-object-example'; +import { createLearningPathNode, createLearningPathTransition } from './learning-path-utils'; const example: LearningPathExample = { createLearningPath: () => { const learningPath = new LearningPath(); - learningPath.hruid = "test_conditions"; + learningPath.hruid = 'test_conditions'; learningPath.language = Language.English; - learningPath.title = "Example learning path with conditional transitions"; - learningPath.description = "This learning path was made for the purpose of testing conditional transitions"; + learningPath.title = 'Example learning path with conditional transitions'; + learningPath.description = 'This learning path was made for the purpose of testing conditional transitions'; const branchingLearningObject = testMultipleChoiceExample.createLearningObject(); const extraExerciseLearningObject = dummyLearningObject( - "test_extra_exercise", Language.English, "Extra exercise (for students with difficulties)" + 'test_extra_exercise', + Language.English, + 'Extra exercise (for students with difficulties)' ).createLearningObject(); const finalLearningObject = dummyLearningObject( - "test_final_learning_object", Language.English, "Final exercise (for everyone)" + 'test_final_learning_object', + Language.English, + 'Final exercise (for everyone)' ).createLearningObject(); const branchingNode = createLearningPathNode( @@ -48,21 +52,11 @@ const example: LearningPathExample = { const transitionToExtraExercise = createLearningPathTransition( branchingNode, 0, - "$[?(@[0] == 0)]", // The answer to the first question was the first one, which says that it is difficult for the student to follow along. + '$[?(@[0] == 0)]', // The answer to the first question was the first one, which says that it is difficult for the student to follow along. extraExerciseNode ); - const directTransitionToFinal = createLearningPathTransition( - branchingNode, - 1, - "$[?(@[0] == 1)]", - finalNode - ); - const transitionExtraExerciseToFinal = createLearningPathTransition( - extraExerciseNode, - 0, - "true", - finalNode - ); + const directTransitionToFinal = createLearningPathTransition(branchingNode, 1, '$[?(@[0] == 1)]', finalNode); + const transitionExtraExerciseToFinal = createLearningPathTransition(extraExerciseNode, 0, 'true', finalNode); branchingNode.transitions = [transitionToExtraExercise, directTransitionToFinal]; extraExerciseNode.transitions = [transitionExtraExerciseToFinal]; @@ -70,5 +64,5 @@ const example: LearningPathExample = { learningPath.nodes = [branchingNode, extraExerciseNode, finalNode]; return learningPath; - } + }, }; diff --git a/backend/tests/test-utils/expectations.ts b/backend/tests/test-utils/expectations.ts index b7e9523b..70fc8c6f 100644 --- a/backend/tests/test-utils/expectations.ts +++ b/backend/tests/test-utils/expectations.ts @@ -1,63 +1,62 @@ -import {AssertionError} from "node:assert"; -import {LearningObject} from "../../src/entities/content/learning-object.entity"; -import {FilteredLearningObject, LearningPath} from "../../src/interfaces/learning-content"; -import {LearningPath as LearningPathEntity} from "../../src/entities/content/learning-path.entity" -import { expect } from "vitest"; +import { AssertionError } from 'node:assert'; +import { LearningObject } from '../../src/entities/content/learning-object.entity'; +import { FilteredLearningObject, LearningPath } from '../../src/interfaces/learning-content'; +import { LearningPath as LearningPathEntity } from '../../src/entities/content/learning-path.entity'; +import { expect } from 'vitest'; // Ignored properties because they belang for example to the class, not to the entity itself. -const IGNORE_PROPERTIES = ["parent"]; +const IGNORE_PROPERTIES = ['parent']; /** * Checks if the actual entity from the database conforms to the entity that was added previously. * @param actual The actual entity retrieved from the database * @param expected The (previously added) entity we would expect to retrieve */ -export function expectToBeCorrectEntity( - actual: {entity: T, name?: string}, - expected: {entity: T, name?: string} -): void { +export function expectToBeCorrectEntity(actual: { entity: T; name?: string }, expected: { entity: T; name?: string }): void { if (!actual.name) { - actual.name = "actual"; + actual.name = 'actual'; } if (!expected.name) { - expected.name = "expected"; + expected.name = 'expected'; } for (const property in expected.entity) { if ( - property !in IGNORE_PROPERTIES - && expected.entity[property] !== undefined // If we don't expect a certain value for a property, we assume it can be filled in by the database however it wants. - && typeof expected.entity[property] !== "function" // Functions obviously are not persisted via the database + property! in IGNORE_PROPERTIES && + expected.entity[property] !== undefined && // If we don't expect a certain value for a property, we assume it can be filled in by the database however it wants. + typeof expected.entity[property] !== 'function' // Functions obviously are not persisted via the database ) { if (!actual.entity.hasOwnProperty(property)) { throw new AssertionError({ - message: `${expected.name} has defined property ${property}, but ${actual.name} is missing it.` + message: `${expected.name} has defined property ${property}, but ${actual.name} is missing it.`, }); } - if (typeof expected.entity[property] === "boolean") { // Sometimes, booleans get represented by numbers 0 and 1 in the objects actual from the database. + if (typeof expected.entity[property] === 'boolean') { + // Sometimes, booleans get represented by numbers 0 and 1 in the objects actual from the database. if (Boolean(expected.entity[property]) !== Boolean(actual.entity[property])) { throw new AssertionError({ message: `${property} was ${expected.entity[property]} in ${expected.name}, - but ${actual.entity[property]} (${Boolean(expected.entity[property])}) in ${actual.name}` + but ${actual.entity[property]} (${Boolean(expected.entity[property])}) in ${actual.name}`, }); } } else if (typeof expected.entity[property] !== typeof actual.entity[property]) { throw new AssertionError({ - message: `${property} has type ${typeof expected.entity[property]} in ${expected.name}, but type ${typeof actual.entity[property]} in ${actual.name}.` + message: `${property} has type ${typeof expected.entity[property]} in ${expected.name}, but type ${typeof actual.entity[property]} in ${actual.name}.`, }); - } else if (typeof expected.entity[property] === "object") { + } else if (typeof expected.entity[property] === 'object') { expectToBeCorrectEntity( { - name: actual.name + "." + property, - entity: actual.entity[property] as object - }, { - name: expected.name + "." + property, - entity: expected.entity[property] as object + name: actual.name + '.' + property, + entity: actual.entity[property] as object, + }, + { + name: expected.name + '.' + property, + entity: expected.entity[property] as object, } ); } else { if (expected.entity[property] !== actual.entity[property]) { throw new AssertionError({ - message: `${property} was ${expected.entity[property]} in ${expected.name}, but ${actual.entity[property]} in ${actual.name}` + message: `${property} was ${expected.entity[property]} in ${expected.name}, but ${actual.entity[property]} in ${actual.name}`, }); } } @@ -78,7 +77,7 @@ export function expectToBeCorrectFilteredLearningObject(filtered: FilteredLearni expect(filtered.key).toEqual(original.hruid); expect(filtered.targetAges).toEqual(original.targetAges); expect(filtered.title).toEqual(original.title); - expect(Boolean(filtered.teacherExclusive)).toEqual(original.teacherExclusive) // !!: Workaround: MikroORM with SQLite returns 0 and 1 instead of booleans. + expect(Boolean(filtered.teacherExclusive)).toEqual(original.teacherExclusive); // !!: Workaround: MikroORM with SQLite returns 0 and 1 instead of booleans. expect(filtered.skosConcepts).toEqual(original.skosConcepts); expect(filtered.estimatedTime).toEqual(original.estimatedTime); expect(filtered.educationalGoals).toEqual(original.educationalGoals); @@ -112,10 +111,10 @@ export function expectToBeCorrectLearningPath( expect(learningPath.description).toEqual(expectedEntity.description); expect(learningPath.title).toEqual(expectedEntity.title); - const keywords = new Set(learningObjectsOnPath.flatMap(it => it.keywords || [])); - expect(new Set(learningPath.keywords.split(' '))).toEqual(keywords) + const keywords = new Set(learningObjectsOnPath.flatMap((it) => it.keywords || [])); + expect(new Set(learningPath.keywords.split(' '))).toEqual(keywords); - const targetAges = new Set(learningObjectsOnPath.flatMap(it => it.targetAges || [])); + const targetAges = new Set(learningObjectsOnPath.flatMap((it) => it.targetAges || [])); expect(new Set(learningPath.target_ages)).toEqual(targetAges); expect(learningPath.min_age).toEqual(Math.min(...targetAges)); expect(learningPath.max_age).toEqual(Math.max(...targetAges)); @@ -124,9 +123,9 @@ export function expectToBeCorrectLearningPath( expect(learningPath.image || null).toEqual(expectedEntity.image); const expectedLearningPathNodes = new Map( - expectedEntity.nodes.map(node => [ - {learningObjectHruid: node.learningObjectHruid, language: node.language, version: node.version}, - {startNode: node.startNode, transitions: node.transitions} + expectedEntity.nodes.map((node) => [ + { learningObjectHruid: node.learningObjectHruid, language: node.language, version: node.version }, + { startNode: node.startNode, transitions: node.transitions }, ]) ); @@ -134,31 +133,18 @@ export function expectToBeCorrectLearningPath( const nodeKey = { learningObjectHruid: node.learningobject_hruid, language: node.language, - version: node.version + version: node.version, }; expect(expectedLearningPathNodes.keys()).toContainEqual(nodeKey); - const expectedNode = [...expectedLearningPathNodes.entries()] - .filter(([key, _]) => - key.learningObjectHruid === nodeKey.learningObjectHruid - && key.language === node.language - && key.version === node.version - )[0][1] + const expectedNode = [...expectedLearningPathNodes.entries()].filter( + ([key, _]) => key.learningObjectHruid === nodeKey.learningObjectHruid && key.language === node.language && key.version === node.version + )[0][1]; expect(node.start_node).toEqual(expectedNode?.startNode); - expect( - new Set(node.transitions.map(it => it.next.hruid)) - ).toEqual( - new Set(expectedNode.transitions.map(it => it.next.learningObjectHruid)) - ); - expect( - new Set(node.transitions.map(it => it.next.language)) - ).toEqual( - new Set(expectedNode.transitions.map(it => it.next.language)) - ); - expect( - new Set(node.transitions.map(it => it.next.version)) - ).toEqual( - new Set(expectedNode.transitions.map(it => it.next.version)) + expect(new Set(node.transitions.map((it) => it.next.hruid))).toEqual( + new Set(expectedNode.transitions.map((it) => it.next.learningObjectHruid)) ); + expect(new Set(node.transitions.map((it) => it.next.language))).toEqual(new Set(expectedNode.transitions.map((it) => it.next.language))); + expect(new Set(node.transitions.map((it) => it.next.version))).toEqual(new Set(expectedNode.transitions.map((it) => it.next.version))); } } diff --git a/backend/tests/test-utils/load-test-asset.ts b/backend/tests/test-utils/load-test-asset.ts index effa0c73..35f6cdbf 100644 --- a/backend/tests/test-utils/load-test-asset.ts +++ b/backend/tests/test-utils/load-test-asset.ts @@ -1,5 +1,5 @@ -import fs from "fs"; -import path from "node:path"; +import fs from 'fs'; +import path from 'node:path'; /** * Load the asset at the given path. From 49f15c50d850c480de3db58e1f7f026675cc3546 Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Tue, 11 Mar 2025 04:40:38 +0100 Subject: [PATCH 138/180] test(backend): Testen DatabaseLearningObjectProvider.getLearningObject[Id]sFromPath toegevoegd --- .../database-learning-object-provider.ts | 7 +- .../learning-paths/point-of-view.d.ts | 1 + .../database-learning-object-provider.test.ts | 68 ++++++++++++++++--- backend/tests/test-utils/expectations.ts | 4 +- 4 files changed, 65 insertions(+), 15 deletions(-) create mode 100644 backend/src/services/learning-paths/point-of-view.d.ts diff --git a/backend/src/services/learning-objects/database-learning-object-provider.ts b/backend/src/services/learning-objects/database-learning-object-provider.ts index 46fc23fe..56aa3a99 100644 --- a/backend/src/services/learning-objects/database-learning-object-provider.ts +++ b/backend/src/services/learning-objects/database-learning-object-provider.ts @@ -10,6 +10,7 @@ import {LearningObject} from "../../entities/content/learning-object.entity"; import {getUrlStringForLearningObject} from "../../util/links"; import processingService from "./processing/processing-service"; import {NotFoundError} from "@mikro-orm/core"; +import learningObjectService from "./learning-object-service"; function convertLearningObject(learningObject: LearningObject | null): FilteredLearningObject | null { @@ -90,7 +91,7 @@ const databaseLearningObjectProvider: LearningObjectProvider = { if (!learningPath) { throw new NotFoundError("The learning path with the given ID could not be found."); } - return learningPath.nodes.map(it => it.learningObjectHruid); // TODO: Determine this based on the submissions of the user. + return learningPath.nodes.map(it => it.learningObjectHruid); }, /** @@ -105,7 +106,7 @@ const databaseLearningObjectProvider: LearningObjectProvider = { } const learningObjects = await Promise.all( learningPath.nodes.map(it => { - const learningObject = this.getLearningObjectById({ + const learningObject = learningObjectService.getLearningObjectById({ hruid: it.learningObjectHruid, language: it.language, version: it.version @@ -116,7 +117,7 @@ const databaseLearningObjectProvider: LearningObjectProvider = { return learningObject; }) ); - return learningObjects.filter(it => it !== null); // TODO: Determine this based on the submissions of the user. + return learningObjects.filter(it => it !== null); } } diff --git a/backend/src/services/learning-paths/point-of-view.d.ts b/backend/src/services/learning-paths/point-of-view.d.ts new file mode 100644 index 00000000..e08685b8 --- /dev/null +++ b/backend/src/services/learning-paths/point-of-view.d.ts @@ -0,0 +1 @@ +type PointOfView = {type: "student", student: Student} | {type: "group", group: Group}; diff --git a/backend/tests/services/learning-objects/database-learning-object-provider.test.ts b/backend/tests/services/learning-objects/database-learning-object-provider.test.ts index 691b29ba..d7870eb9 100644 --- a/backend/tests/services/learning-objects/database-learning-object-provider.test.ts +++ b/backend/tests/services/learning-objects/database-learning-object-provider.test.ts @@ -1,29 +1,37 @@ import {beforeAll, describe, expect, it} from "vitest"; import {setupTestApp} from "../../setup-tests"; -import {getLearningObjectRepository} from "../../../src/data/repositories"; +import {getLearningObjectRepository, getLearningPathRepository} from "../../../src/data/repositories"; import example from "../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example"; import {LearningObject} from "../../../src/entities/content/learning-object.entity"; import databaseLearningObjectProvider from "../../../src/services/learning-objects/database-learning-object-provider"; -import { - createExampleLearningObjectWithAttachments -} from "../../test-assets/learning-objects/create-example-learning-object-with-attachments"; import {expectToBeCorrectFilteredLearningObject} from "../../test-utils/expectations"; import {FilteredLearningObject} from "../../../src/interfaces/learning-content"; import {Language} from "../../../src/entities/content/language"; +import learningObjectExample from "../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example"; +import learningPathExample from "../../test-assets/learning-paths/pn-werking-example"; +import {LearningPath} from "../../../src/entities/content/learning-path.entity"; -async function initExampleData(): Promise { - let learningObjectRepo = getLearningObjectRepository(); - let exampleLearningObject = createExampleLearningObjectWithAttachments(example); - await learningObjectRepo.insert(exampleLearningObject); - return exampleLearningObject; +async function initExampleData(): Promise<{learningObject: LearningObject, learningPath: LearningPath}> { + const learningObjectRepo = getLearningObjectRepository(); + const learningPathRepo = getLearningPathRepository(); + let learningObject = learningObjectExample.createLearningObject(); + let learningPath = learningPathExample.createLearningPath(); + await learningObjectRepo.save(learningObject); + await learningPathRepo.save(learningPath); + return { learningObject, learningPath }; } +const EXPECTED_TITLE_FROM_DWENGO_LEARNING_OBJECT = "Notebook opslaan"; + describe("DatabaseLearningObjectProvider", () => { let exampleLearningObject: LearningObject; + let exampleLearningPath: LearningPath; beforeAll(async () => { await setupTestApp(); - exampleLearningObject = await initExampleData(); + let exampleData = await initExampleData(); + exampleLearningObject = exampleData.learningObject; + exampleLearningPath = exampleData.learningPath; }); describe("getLearningObjectById", () => { it("should return the learning object when it is queried by its id", async () => { @@ -54,5 +62,45 @@ describe("DatabaseLearningObjectProvider", () => { const result = await databaseLearningObjectProvider.getLearningObjectHTML(exampleLearningObject); expect(result).toEqual(example.getHTMLRendering()); }); + it("should return null for a non-existing learning object", async () => { + const result = await databaseLearningObjectProvider.getLearningObjectHTML({ + hruid: "non_existing_hruid", + language: Language.Dutch + }); + expect(result).toBeNull(); + }); + }); + describe("getLearningObjectIdsFromPath", () => { + it("should return all learning object IDs from a path", async () => { + const result = await databaseLearningObjectProvider.getLearningObjectIdsFromPath(exampleLearningPath); + expect(new Set(result)) + .toEqual(new Set(exampleLearningPath.nodes.map(it => it.learningObjectHruid))); + }); + it("should throw an error if queried with a path identifier for which there is no learning path", async () => { + await expect((async () => { + await databaseLearningObjectProvider.getLearningObjectIdsFromPath({ + hruid: "non_existing_hruid", + language: Language.Dutch + }); + })()).rejects.toThrowError(); + }); + }); + describe("getLearningObjectsFromPath", () => { + it("should correctly return all learning objects which are on the path, even those who are not in the database", async () => { + const result = await databaseLearningObjectProvider.getLearningObjectsFromPath(exampleLearningPath); + expect(result.length).toBe(exampleLearningPath.nodes.length); + expect(new Set(result.map(it => it.key))) + .toEqual(new Set(exampleLearningPath.nodes.map(it => it.learningObjectHruid))); + + expect(result.map(it => it.title)).toContainEqual(EXPECTED_TITLE_FROM_DWENGO_LEARNING_OBJECT); + }); + it("should throw an error if queried with a path identifier for which there is no learning path", async () => { + await expect((async () => { + await databaseLearningObjectProvider.getLearningObjectsFromPath({ + hruid: "non_existing_hruid", + language: Language.Dutch + }); + })()).rejects.toThrowError(); + }); }); }); diff --git a/backend/tests/test-utils/expectations.ts b/backend/tests/test-utils/expectations.ts index 19c2408d..e8e70845 100644 --- a/backend/tests/test-utils/expectations.ts +++ b/backend/tests/test-utils/expectations.ts @@ -78,7 +78,7 @@ export function expectToBeCorrectFilteredLearningObject(filtered: FilteredLearni expect(filtered.key).toEqual(original.hruid); expect(filtered.targetAges).toEqual(original.targetAges); expect(filtered.title).toEqual(original.title); - expect(!!filtered.teacherExclusive).toEqual(original.teacherExclusive) // !!: Workaround: MikroORM with SQLite returns 0 and 1 instead of booleans. + expect(!!filtered.teacherExclusive).toEqual(!!original.teacherExclusive) // !!: Workaround: MikroORM with SQLite returns 0 and 1 instead of booleans. expect(filtered.skosConcepts).toEqual(original.skosConcepts); expect(filtered.estimatedTime).toEqual(original.estimatedTime); expect(filtered.educationalGoals).toEqual(original.educationalGoals); @@ -87,7 +87,7 @@ export function expectToBeCorrectFilteredLearningObject(filtered: FilteredLearni expect(filtered.returnValue?.callback_url).toEqual(original.returnValue.callbackUrl); expect(filtered.returnValue?.callback_schema).toEqual(JSON.parse(original.returnValue.callbackSchema)); expect(filtered.contentType).toEqual(original.contentType); - expect(filtered.contentLocation).toEqual(original.contentLocation || null); + expect(filtered.contentLocation || null).toEqual(original.contentLocation || null); expect(filtered.htmlUrl).toContain(`/${original.hruid}/html`); expect(filtered.htmlUrl).toContain(`language=${original.language}`); expect(filtered.htmlUrl).toContain(`version=${original.version}`); From 28e0a7b45d1fc0c4d86bf2a9cbb62a22079f44ad Mon Sep 17 00:00:00 2001 From: Lint Action Date: Tue, 11 Mar 2025 03:45:58 +0000 Subject: [PATCH 139/180] style: fix linting issues met ESLint --- .../database-learning-object-provider.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/tests/services/learning-objects/database-learning-object-provider.test.ts b/backend/tests/services/learning-objects/database-learning-object-provider.test.ts index 9bd9d36a..78d8d3a1 100644 --- a/backend/tests/services/learning-objects/database-learning-object-provider.test.ts +++ b/backend/tests/services/learning-objects/database-learning-object-provider.test.ts @@ -14,8 +14,8 @@ import {LearningPath} from "../../../src/entities/content/learning-path.entity"; async function initExampleData(): Promise<{learningObject: LearningObject, learningPath: LearningPath}> { const learningObjectRepo = getLearningObjectRepository(); const learningPathRepo = getLearningPathRepository(); - let learningObject = learningObjectExample.createLearningObject(); - let learningPath = learningPathExample.createLearningPath(); + const learningObject = learningObjectExample.createLearningObject(); + const learningPath = learningPathExample.createLearningPath(); await learningObjectRepo.save(learningObject); await learningPathRepo.save(learningPath); return { learningObject, learningPath }; @@ -29,7 +29,7 @@ describe('DatabaseLearningObjectProvider', () => { beforeAll(async () => { await setupTestApp(); - let exampleData = await initExampleData(); + const exampleData = await initExampleData(); exampleLearningObject = exampleData.learningObject; exampleLearningPath = exampleData.learningPath; }); From 75d80f65f578f081dcea96164caa277a6c4d49e2 Mon Sep 17 00:00:00 2001 From: Lint Action Date: Tue, 11 Mar 2025 03:46:02 +0000 Subject: [PATCH 140/180] style: fix linting issues met Prettier --- .../database-learning-object-provider.ts | 27 +++--- .../learning-paths/point-of-view.d.ts | 2 +- .../database-learning-object-provider.test.ts | 82 ++++++++++--------- 3 files changed, 54 insertions(+), 57 deletions(-) diff --git a/backend/src/services/learning-objects/database-learning-object-provider.ts b/backend/src/services/learning-objects/database-learning-object-provider.ts index 57ef37bb..186bdffd 100644 --- a/backend/src/services/learning-objects/database-learning-object-provider.ts +++ b/backend/src/services/learning-objects/database-learning-object-provider.ts @@ -1,17 +1,12 @@ -import {LearningObjectProvider} from "./learning-object-provider"; -import { - FilteredLearningObject, - LearningObjectIdentifier, - LearningPathIdentifier -} from "../../interfaces/learning-content"; -import {getLearningObjectRepository, getLearningPathRepository} from "../../data/repositories"; -import {Language} from "../../entities/content/language"; -import {LearningObject} from "../../entities/content/learning-object.entity"; -import {getUrlStringForLearningObject} from "../../util/links"; -import processingService from "./processing/processing-service"; -import {NotFoundError} from "@mikro-orm/core"; -import learningObjectService from "./learning-object-service"; - +import { LearningObjectProvider } from './learning-object-provider'; +import { FilteredLearningObject, LearningObjectIdentifier, LearningPathIdentifier } from '../../interfaces/learning-content'; +import { getLearningObjectRepository, getLearningPathRepository } from '../../data/repositories'; +import { Language } from '../../entities/content/language'; +import { LearningObject } from '../../entities/content/learning-object.entity'; +import { getUrlStringForLearningObject } from '../../util/links'; +import processingService from './processing/processing-service'; +import { NotFoundError } from '@mikro-orm/core'; +import learningObjectService from './learning-object-service'; function convertLearningObject(learningObject: LearningObject | null): FilteredLearningObject | null { if (!learningObject) { @@ -110,8 +105,8 @@ const databaseLearningObjectProvider: LearningObjectProvider = { return learningObject; }) ); - return learningObjects.filter(it => it !== null); - } + return learningObjects.filter((it) => it !== null); + }, }; export default databaseLearningObjectProvider; diff --git a/backend/src/services/learning-paths/point-of-view.d.ts b/backend/src/services/learning-paths/point-of-view.d.ts index e08685b8..14190090 100644 --- a/backend/src/services/learning-paths/point-of-view.d.ts +++ b/backend/src/services/learning-paths/point-of-view.d.ts @@ -1 +1 @@ -type PointOfView = {type: "student", student: Student} | {type: "group", group: Group}; +type PointOfView = { type: 'student'; student: Student } | { type: 'group'; group: Group }; diff --git a/backend/tests/services/learning-objects/database-learning-object-provider.test.ts b/backend/tests/services/learning-objects/database-learning-object-provider.test.ts index 78d8d3a1..692a72de 100644 --- a/backend/tests/services/learning-objects/database-learning-object-provider.test.ts +++ b/backend/tests/services/learning-objects/database-learning-object-provider.test.ts @@ -1,17 +1,17 @@ -import {beforeAll, describe, expect, it} from "vitest"; -import {setupTestApp} from "../../setup-tests"; -import {getLearningObjectRepository, getLearningPathRepository} from "../../../src/data/repositories"; -import example from "../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example"; -import {LearningObject} from "../../../src/entities/content/learning-object.entity"; -import databaseLearningObjectProvider from "../../../src/services/learning-objects/database-learning-object-provider"; -import {expectToBeCorrectFilteredLearningObject} from "../../test-utils/expectations"; -import {FilteredLearningObject} from "../../../src/interfaces/learning-content"; -import {Language} from "../../../src/entities/content/language"; -import learningObjectExample from "../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example"; -import learningPathExample from "../../test-assets/learning-paths/pn-werking-example"; -import {LearningPath} from "../../../src/entities/content/learning-path.entity"; +import { beforeAll, describe, expect, it } from 'vitest'; +import { setupTestApp } from '../../setup-tests'; +import { getLearningObjectRepository, getLearningPathRepository } from '../../../src/data/repositories'; +import example from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example'; +import { LearningObject } from '../../../src/entities/content/learning-object.entity'; +import databaseLearningObjectProvider from '../../../src/services/learning-objects/database-learning-object-provider'; +import { expectToBeCorrectFilteredLearningObject } from '../../test-utils/expectations'; +import { FilteredLearningObject } from '../../../src/interfaces/learning-content'; +import { Language } from '../../../src/entities/content/language'; +import learningObjectExample from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example'; +import learningPathExample from '../../test-assets/learning-paths/pn-werking-example'; +import { LearningPath } from '../../../src/entities/content/learning-path.entity'; -async function initExampleData(): Promise<{learningObject: LearningObject, learningPath: LearningPath}> { +async function initExampleData(): Promise<{ learningObject: LearningObject; learningPath: LearningPath }> { const learningObjectRepo = getLearningObjectRepository(); const learningPathRepo = getLearningPathRepository(); const learningObject = learningObjectExample.createLearningObject(); @@ -21,7 +21,7 @@ async function initExampleData(): Promise<{learningObject: LearningObject, learn return { learningObject, learningPath }; } -const EXPECTED_TITLE_FROM_DWENGO_LEARNING_OBJECT = "Notebook opslaan"; +const EXPECTED_TITLE_FROM_DWENGO_LEARNING_OBJECT = 'Notebook opslaan'; describe('DatabaseLearningObjectProvider', () => { let exampleLearningObject: LearningObject; @@ -62,45 +62,47 @@ describe('DatabaseLearningObjectProvider', () => { const result = await databaseLearningObjectProvider.getLearningObjectHTML(exampleLearningObject); expect(result).toEqual(example.getHTMLRendering()); }); - it("should return null for a non-existing learning object", async () => { + it('should return null for a non-existing learning object', async () => { const result = await databaseLearningObjectProvider.getLearningObjectHTML({ - hruid: "non_existing_hruid", - language: Language.Dutch + hruid: 'non_existing_hruid', + language: Language.Dutch, }); expect(result).toBeNull(); }); }); - describe("getLearningObjectIdsFromPath", () => { - it("should return all learning object IDs from a path", async () => { + describe('getLearningObjectIdsFromPath', () => { + it('should return all learning object IDs from a path', async () => { const result = await databaseLearningObjectProvider.getLearningObjectIdsFromPath(exampleLearningPath); - expect(new Set(result)) - .toEqual(new Set(exampleLearningPath.nodes.map(it => it.learningObjectHruid))); + expect(new Set(result)).toEqual(new Set(exampleLearningPath.nodes.map((it) => it.learningObjectHruid))); }); - it("should throw an error if queried with a path identifier for which there is no learning path", async () => { - await expect((async () => { - await databaseLearningObjectProvider.getLearningObjectIdsFromPath({ - hruid: "non_existing_hruid", - language: Language.Dutch - }); - })()).rejects.toThrowError(); + it('should throw an error if queried with a path identifier for which there is no learning path', async () => { + await expect( + (async () => { + await databaseLearningObjectProvider.getLearningObjectIdsFromPath({ + hruid: 'non_existing_hruid', + language: Language.Dutch, + }); + })() + ).rejects.toThrowError(); }); }); - describe("getLearningObjectsFromPath", () => { - it("should correctly return all learning objects which are on the path, even those who are not in the database", async () => { + describe('getLearningObjectsFromPath', () => { + it('should correctly return all learning objects which are on the path, even those who are not in the database', async () => { const result = await databaseLearningObjectProvider.getLearningObjectsFromPath(exampleLearningPath); expect(result.length).toBe(exampleLearningPath.nodes.length); - expect(new Set(result.map(it => it.key))) - .toEqual(new Set(exampleLearningPath.nodes.map(it => it.learningObjectHruid))); + expect(new Set(result.map((it) => it.key))).toEqual(new Set(exampleLearningPath.nodes.map((it) => it.learningObjectHruid))); - expect(result.map(it => it.title)).toContainEqual(EXPECTED_TITLE_FROM_DWENGO_LEARNING_OBJECT); + expect(result.map((it) => it.title)).toContainEqual(EXPECTED_TITLE_FROM_DWENGO_LEARNING_OBJECT); }); - it("should throw an error if queried with a path identifier for which there is no learning path", async () => { - await expect((async () => { - await databaseLearningObjectProvider.getLearningObjectsFromPath({ - hruid: "non_existing_hruid", - language: Language.Dutch - }); - })()).rejects.toThrowError(); + it('should throw an error if queried with a path identifier for which there is no learning path', async () => { + await expect( + (async () => { + await databaseLearningObjectProvider.getLearningObjectsFromPath({ + hruid: 'non_existing_hruid', + language: Language.Dutch, + }); + })() + ).rejects.toThrowError(); }); }); }); From 19cd9c43878a80f0fffdc7949a191528790bbb19 Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Tue, 11 Mar 2025 04:54:19 +0100 Subject: [PATCH 141/180] fix(backend): Conflicten met linter opgelost --- .../dummy/dummy-learning-object-example.ts | 2 +- .../learning-objects/dummy/rendering.html | 0 .../learning-objects/dummy/rendering.txt | 1 + .../pn-werkingnotebooks-example.ts | 2 +- .../pn-werkingnotebooks/rendering.html | 47 ------------------- .../pn-werkingnotebooks/rendering.txt | 20 ++++++++ .../{rendering.html => rendering.txt} | 0 .../test-essay/test-essay-example.ts | 2 +- .../{rendering.html => rendering.txt} | 4 +- .../test-multiple-choice-example.ts | 2 +- backend/tests/test-utils/expectations.ts | 2 +- 11 files changed, 28 insertions(+), 54 deletions(-) delete mode 100644 backend/tests/test-assets/learning-objects/dummy/rendering.html create mode 100644 backend/tests/test-assets/learning-objects/dummy/rendering.txt delete mode 100644 backend/tests/test-assets/learning-objects/pn-werkingnotebooks/rendering.html create mode 100644 backend/tests/test-assets/learning-objects/pn-werkingnotebooks/rendering.txt rename backend/tests/test-assets/learning-objects/test-essay/{rendering.html => rendering.txt} (100%) rename backend/tests/test-assets/learning-objects/test-multiple-choice/{rendering.html => rendering.txt} (92%) diff --git a/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts b/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts index 5b773d09..6dbe54b0 100644 --- a/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts +++ b/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts @@ -22,6 +22,6 @@ export function dummyLearningObject(hruid: string, language: Language, title: st return learningObject; }, createAttachment: {}, - getHTMLRendering: () => loadTestAsset('learning-objects/dummy/rendering.html').toString(), + getHTMLRendering: () => loadTestAsset('learning-objects/dummy/rendering.txt').toString(), }; } diff --git a/backend/tests/test-assets/learning-objects/dummy/rendering.html b/backend/tests/test-assets/learning-objects/dummy/rendering.html deleted file mode 100644 index e69de29b..00000000 diff --git a/backend/tests/test-assets/learning-objects/dummy/rendering.txt b/backend/tests/test-assets/learning-objects/dummy/rendering.txt new file mode 100644 index 00000000..f3ae8006 --- /dev/null +++ b/backend/tests/test-assets/learning-objects/dummy/rendering.txt @@ -0,0 +1 @@ +Dummy content diff --git a/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.ts b/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.ts index 5bca09a6..600a4305 100644 --- a/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.ts +++ b/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.ts @@ -67,6 +67,6 @@ const example: LearningObjectExample = { return att; }, }, - getHTMLRendering: () => loadTestAsset(`${ASSETS_PREFIX}/rendering.html`).toString(), + getHTMLRendering: () => loadTestAsset(`${ASSETS_PREFIX}/rendering.txt`).toString(), }; export default example; diff --git a/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/rendering.html b/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/rendering.html deleted file mode 100644 index ab9bd34e..00000000 --- a/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/rendering.html +++ /dev/null @@ -1,47 +0,0 @@ -

- - - - Werken met notebooks -

-

- Het lesmateriaal van 'Python in wiskunde en STEM' wordt aangeboden in de vorm van interactieve notebooks. Notebooks zijn digitale documenten die zowel uitvoerbare code bevatten als tekst, afbeeldingen, video, hyperlinks ... -

-

Nieuwe begrippen worden aangebracht via tekstuele uitleg, video en afbeeldingen.

-

- Er zijn uitgewerkte voorbeelden met daarnaast ook kleine en grote opdrachten. In deze opdrachten zal je aangereikte code kunnen - uitvoeren, maar ook zelf code opstellen. -

-

- De code die in de notebooks gebruikt wordt, is Python versie 3. We kozen voor Python omdat dit een heel toegankelijke programmeertaal is, die vaak - ook intuC/tief is. Python is bovendien bezig aan een opmars en wordt gebruikt door bedrijven, zoals Google, NASA, Netflix, Uber, AstraZeneca, - Barco, Instagram en YouTube. -

-

- We kozen voor notebooks omdat daar enkele belangrijke voordelen aan verbonden zijn: leerkrachten moeten geen geavanceerde installaties doen om de - notebooks te gebruiken, leerkrachten kunnen verschillende soorten van lesinhouden aanbieden via C)C)n platform, de notebooks zijn interactief, - leerlingen bouwen de oplossing van een probleem stap voor stap op in de notebook waardoor dat proces zichtbaar is voor de leerkracht (Jeroen Van der Hooft, 2023). -

-
-

- Klik je op onderstaande knop 'Open notebooks', dan word je doorgestuurd naar een andere website waar jouw persoonlijke notebooks ingeladen - worden. (Dit kan even duren.) -

-

- Links op het scherm vind je er twee bestanden met extensie .ipynb. Dit zijn de twee notebooks waarin je resp. een overzicht krijgt van de - opbouw en mogelijkheden en hoe je er mee aan de slag kan. Dubbelklik op de bestandsnaam om een notebook te openen. -

-

Je ziet er ook een map images met de afbeeldingen die in de notebooks getoond worden.

-

- In deze eerste twee notebooks leer je hoe de notebooks zijn opgevat en hoe je ermee aan de slag kan. Na het doorlopen van beide notebooks heb je - een goed idee van hoe onze Python notebooks zijn opgevat. -

-

- -

diff --git a/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/rendering.txt b/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/rendering.txt new file mode 100644 index 00000000..af596243 --- /dev/null +++ b/backend/tests/test-assets/learning-objects/pn-werkingnotebooks/rendering.txt @@ -0,0 +1,20 @@ +

+ + + + Werken met notebooks +

+

Het lesmateriaal van 'Python in wiskunde en STEM' wordt aangeboden in de vorm van interactieve notebooks. Notebooks zijn digitale documenten die zowel uitvoerbare code bevatten als tekst, afbeeldingen, video, hyperlinks ...

+

Nieuwe begrippen worden aangebracht via tekstuele uitleg, video en afbeeldingen.

+

Er zijn uitgewerkte voorbeelden met daarnaast ook kleine en grote opdrachten. In deze opdrachten zal je aangereikte code kunnen uitvoeren, maar ook zelf code opstellen.

+

De code die in de notebooks gebruikt wordt, is Python versie 3. We kozen voor Python omdat dit een heel toegankelijke programmeertaal is, die vaak ook intuC/tief is. +Python is bovendien bezig aan een opmars en wordt gebruikt door bedrijven, zoals Google, NASA, Netflix, Uber, AstraZeneca, Barco, Instagram en YouTube.

+

We kozen voor notebooks omdat daar enkele belangrijke voordelen aan verbonden zijn: leerkrachten moeten geen geavanceerde installaties doen om de notebooks te gebruiken, leerkrachten kunnen verschillende soorten van lesinhouden aanbieden via C)C)n platform, de notebooks zijn interactief, leerlingen bouwen de oplossing van een probleem stap voor stap op in de notebook waardoor dat proces zichtbaar is voor de leerkracht (Jeroen Van der Hooft, 2023).

+
+

Klik je op onderstaande knop 'Open notebooks', dan word je doorgestuurd naar een andere website waar jouw persoonlijke notebooks ingeladen worden. (Dit kan even duren.)

+

Links op het scherm vind je er twee bestanden met extensie .ipynb. +Dit zijn de twee notebooks waarin je resp. een overzicht krijgt van de opbouw en mogelijkheden en hoe je er mee aan de slag kan. Dubbelklik op de bestandsnaam om een notebook te openen.

+

Je ziet er ook een map images met de afbeeldingen die in de notebooks getoond worden.

+

In deze eerste twee notebooks leer je hoe de notebooks zijn opgevat en hoe je ermee aan de slag kan. +Na het doorlopen van beide notebooks heb je een goed idee van hoe onze Python notebooks zijn opgevat.

+

diff --git a/backend/tests/test-assets/learning-objects/test-essay/rendering.html b/backend/tests/test-assets/learning-objects/test-essay/rendering.txt similarity index 100% rename from backend/tests/test-assets/learning-objects/test-essay/rendering.html rename to backend/tests/test-assets/learning-objects/test-essay/rendering.txt diff --git a/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts b/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts index 7a2f54d9..b1ff330e 100644 --- a/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts +++ b/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts @@ -18,7 +18,7 @@ const example: LearningObjectExample = { return learningObject; }, createAttachment: {}, - getHTMLRendering: () => loadTestAsset('learning-objects/test-essay/rendering.html').toString(), + getHTMLRendering: () => loadTestAsset('learning-objects/test-essay/rendering.txt').toString(), }; export default example; diff --git a/backend/tests/test-assets/learning-objects/test-multiple-choice/rendering.html b/backend/tests/test-assets/learning-objects/test-multiple-choice/rendering.txt similarity index 92% rename from backend/tests/test-assets/learning-objects/test-multiple-choice/rendering.html rename to backend/tests/test-assets/learning-objects/test-multiple-choice/rendering.txt index 513a29a5..c1829f24 100644 --- a/backend/tests/test-assets/learning-objects/test-multiple-choice/rendering.html +++ b/backend/tests/test-assets/learning-objects/test-multiple-choice/rendering.txt @@ -3,11 +3,11 @@

MC basic

Are you following along well with the class?

- +
- +
diff --git a/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts b/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts index 52b6adbe..cfb0b5a2 100644 --- a/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts +++ b/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts @@ -18,7 +18,7 @@ const example: LearningObjectExample = { return learningObject; }, createAttachment: {}, - getHTMLRendering: () => loadTestAsset('learning-objects/test-multiple-choice/rendering.html').toString(), + getHTMLRendering: () => loadTestAsset('learning-objects/test-multiple-choice/rendering.txt').toString(), }; export default example; diff --git a/backend/tests/test-utils/expectations.ts b/backend/tests/test-utils/expectations.ts index f9fe2c68..0fe63811 100644 --- a/backend/tests/test-utils/expectations.ts +++ b/backend/tests/test-utils/expectations.ts @@ -77,7 +77,7 @@ export function expectToBeCorrectFilteredLearningObject(filtered: FilteredLearni expect(filtered.key).toEqual(original.hruid); expect(filtered.targetAges).toEqual(original.targetAges); expect(filtered.title).toEqual(original.title); - expect(Boolean(filtered.teacherExclusive)).toEqual(original.teacherExclusive); // !!: Workaround: MikroORM with SQLite returns 0 and 1 instead of booleans. + expect(Boolean(filtered.teacherExclusive)).toEqual(Boolean(original.teacherExclusive)); expect(filtered.skosConcepts).toEqual(original.skosConcepts); expect(filtered.estimatedTime).toEqual(original.estimatedTime); expect(filtered.educationalGoals).toEqual(original.educationalGoals); From b630b9a45d12498958840fa52b3557c91aadaf75 Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Tue, 11 Mar 2025 05:07:35 +0100 Subject: [PATCH 142/180] test(backend): Testen LearningObjectService.getLearningObject[Id]sFromPath toegevoegd --- .../learning-object-service.test.ts | 65 +++++++++++++++---- 1 file changed, 54 insertions(+), 11 deletions(-) diff --git a/backend/tests/services/learning-objects/learning-object-service.test.ts b/backend/tests/services/learning-objects/learning-object-service.test.ts index 26f03595..f4e40747 100644 --- a/backend/tests/services/learning-objects/learning-object-service.test.ts +++ b/backend/tests/services/learning-objects/learning-object-service.test.ts @@ -1,12 +1,14 @@ -import { beforeAll, describe, expect, it } from 'vitest'; -import { setupTestApp } from '../../setup-tests'; -import { LearningObject } from '../../../src/entities/content/learning-object.entity'; -import { getLearningObjectRepository } from '../../../src/data/repositories'; +import {beforeAll, describe, expect, it} from 'vitest'; +import {setupTestApp} from '../../setup-tests'; +import {LearningObject} from '../../../src/entities/content/learning-object.entity'; +import {getLearningObjectRepository, getLearningPathRepository} from '../../../src/data/repositories'; import learningObjectExample from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example'; import learningObjectService from '../../../src/services/learning-objects/learning-object-service'; -import { LearningObjectIdentifier } from '../../../src/interfaces/learning-content'; -import { Language } from '../../../src/entities/content/language'; -import { EnvVars, getEnvVar } from '../../../src/util/envvars'; +import {LearningObjectIdentifier, LearningPathIdentifier} from '../../../src/interfaces/learning-content'; +import {Language} from '../../../src/entities/content/language'; +import {EnvVars, getEnvVar} from '../../../src/util/envvars'; +import {LearningPath} from "../../../src/entities/content/learning-path.entity"; +import learningPathExample from "../../test-assets/learning-paths/pn-werking-example"; const TEST_LEARNING_OBJECT_TITLE = 'Test title'; const EXPECTED_DWENGO_LEARNING_OBJECT_TITLE = 'Werken met notebooks'; @@ -16,20 +18,31 @@ const DWENGO_TEST_LEARNING_OBJECT_ID: LearningObjectIdentifier = { version: 3, }; -async function initExampleData(): Promise { +const DWENGO_TEST_LEARNING_PATH_ID: LearningPathIdentifier = { + hruid: 'pn_werking', + language: Language.Dutch +}; +const DWENGO_TEST_LEARNING_PATH_HRUIDS = new Set(["pn_werkingnotebooks", "pn_werkingnotebooks2", "pn_werkingnotebooks3"]); + +async function initExampleData(): Promise<{ learningObject: LearningObject; learningPath: LearningPath }> { const learningObjectRepo = getLearningObjectRepository(); + const learningPathRepo = getLearningPathRepository(); const learningObject = learningObjectExample.createLearningObject(); - learningObject.title = TEST_LEARNING_OBJECT_TITLE; + const learningPath = learningPathExample.createLearningPath(); await learningObjectRepo.save(learningObject); - return learningObject; + await learningPathRepo.save(learningPath); + return { learningObject, learningPath }; } describe('LearningObjectService', () => { let exampleLearningObject: LearningObject; + let exampleLearningPath: LearningPath; beforeAll(async () => { await setupTestApp(); - exampleLearningObject = await initExampleData(); + const exampleData = await initExampleData(); + exampleLearningObject = exampleData.learningObject; + exampleLearningPath = exampleData.learningPath; }); describe('getLearningObjectById', () => { @@ -80,4 +93,34 @@ describe('LearningObjectService', () => { expect(result).toBeNull(); }); }); + + describe('getLearningObjectsFromPath', () => { + it("returns all learning objects when a learning path in the database is queried", async () => { + const result = await learningObjectService.getLearningObjectsFromPath(exampleLearningPath); + expect(result.map(it => it.key)).toEqual(exampleLearningPath.nodes.map(it => it.learningObjectHruid)); + }); + it("also returns all learning objects when a learning path from the Dwengo API is queried", async () => { + const result = await learningObjectService.getLearningObjectsFromPath(DWENGO_TEST_LEARNING_PATH_ID); + expect(new Set(result.map(it => it.key))).toEqual(DWENGO_TEST_LEARNING_PATH_HRUIDS); + }); + it("returns an empty list when queried with a non-existing learning path id", async () => { + const result = await learningObjectService.getLearningObjectsFromPath({hruid: "non_existing", language: Language.Dutch}); + expect(result).toEqual([]); + }); + }); + + describe('getLearningObjectIdsFromPath', () => { + it("returns all learning objects when a learning path in the database is queried", async () => { + const result = await learningObjectService.getLearningObjectIdsFromPath(exampleLearningPath); + expect(result).toEqual(exampleLearningPath.nodes.map(it => it.learningObjectHruid)); + }); + it("also returns all learning object hruids when a learning path from the Dwengo API is queried", async () => { + const result = await learningObjectService.getLearningObjectIdsFromPath(DWENGO_TEST_LEARNING_PATH_ID); + expect(new Set(result)).toEqual(DWENGO_TEST_LEARNING_PATH_HRUIDS); + }); + it("returns an empty list when queried with a non-existing learning path id", async () => { + const result = await learningObjectService.getLearningObjectIdsFromPath({hruid: "non_existing", language: Language.Dutch}); + expect(result).toEqual([]); + }); + }); }); From 466b9b8d177093e6b8c61804b82b2b2a69a81c0f Mon Sep 17 00:00:00 2001 From: Lint Action Date: Tue, 11 Mar 2025 04:08:12 +0000 Subject: [PATCH 143/180] style: fix linting issues met Prettier --- .../learning-object-service.test.ts | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/backend/tests/services/learning-objects/learning-object-service.test.ts b/backend/tests/services/learning-objects/learning-object-service.test.ts index f4e40747..f748d9f3 100644 --- a/backend/tests/services/learning-objects/learning-object-service.test.ts +++ b/backend/tests/services/learning-objects/learning-object-service.test.ts @@ -1,14 +1,14 @@ -import {beforeAll, describe, expect, it} from 'vitest'; -import {setupTestApp} from '../../setup-tests'; -import {LearningObject} from '../../../src/entities/content/learning-object.entity'; -import {getLearningObjectRepository, getLearningPathRepository} from '../../../src/data/repositories'; +import { beforeAll, describe, expect, it } from 'vitest'; +import { setupTestApp } from '../../setup-tests'; +import { LearningObject } from '../../../src/entities/content/learning-object.entity'; +import { getLearningObjectRepository, getLearningPathRepository } from '../../../src/data/repositories'; import learningObjectExample from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example'; import learningObjectService from '../../../src/services/learning-objects/learning-object-service'; -import {LearningObjectIdentifier, LearningPathIdentifier} from '../../../src/interfaces/learning-content'; -import {Language} from '../../../src/entities/content/language'; -import {EnvVars, getEnvVar} from '../../../src/util/envvars'; -import {LearningPath} from "../../../src/entities/content/learning-path.entity"; -import learningPathExample from "../../test-assets/learning-paths/pn-werking-example"; +import { LearningObjectIdentifier, LearningPathIdentifier } from '../../../src/interfaces/learning-content'; +import { Language } from '../../../src/entities/content/language'; +import { EnvVars, getEnvVar } from '../../../src/util/envvars'; +import { LearningPath } from '../../../src/entities/content/learning-path.entity'; +import learningPathExample from '../../test-assets/learning-paths/pn-werking-example'; const TEST_LEARNING_OBJECT_TITLE = 'Test title'; const EXPECTED_DWENGO_LEARNING_OBJECT_TITLE = 'Werken met notebooks'; @@ -20,9 +20,9 @@ const DWENGO_TEST_LEARNING_OBJECT_ID: LearningObjectIdentifier = { const DWENGO_TEST_LEARNING_PATH_ID: LearningPathIdentifier = { hruid: 'pn_werking', - language: Language.Dutch + language: Language.Dutch, }; -const DWENGO_TEST_LEARNING_PATH_HRUIDS = new Set(["pn_werkingnotebooks", "pn_werkingnotebooks2", "pn_werkingnotebooks3"]); +const DWENGO_TEST_LEARNING_PATH_HRUIDS = new Set(['pn_werkingnotebooks', 'pn_werkingnotebooks2', 'pn_werkingnotebooks3']); async function initExampleData(): Promise<{ learningObject: LearningObject; learningPath: LearningPath }> { const learningObjectRepo = getLearningObjectRepository(); @@ -95,31 +95,31 @@ describe('LearningObjectService', () => { }); describe('getLearningObjectsFromPath', () => { - it("returns all learning objects when a learning path in the database is queried", async () => { + it('returns all learning objects when a learning path in the database is queried', async () => { const result = await learningObjectService.getLearningObjectsFromPath(exampleLearningPath); - expect(result.map(it => it.key)).toEqual(exampleLearningPath.nodes.map(it => it.learningObjectHruid)); + expect(result.map((it) => it.key)).toEqual(exampleLearningPath.nodes.map((it) => it.learningObjectHruid)); }); - it("also returns all learning objects when a learning path from the Dwengo API is queried", async () => { + it('also returns all learning objects when a learning path from the Dwengo API is queried', async () => { const result = await learningObjectService.getLearningObjectsFromPath(DWENGO_TEST_LEARNING_PATH_ID); - expect(new Set(result.map(it => it.key))).toEqual(DWENGO_TEST_LEARNING_PATH_HRUIDS); + expect(new Set(result.map((it) => it.key))).toEqual(DWENGO_TEST_LEARNING_PATH_HRUIDS); }); - it("returns an empty list when queried with a non-existing learning path id", async () => { - const result = await learningObjectService.getLearningObjectsFromPath({hruid: "non_existing", language: Language.Dutch}); + it('returns an empty list when queried with a non-existing learning path id', async () => { + const result = await learningObjectService.getLearningObjectsFromPath({ hruid: 'non_existing', language: Language.Dutch }); expect(result).toEqual([]); }); }); describe('getLearningObjectIdsFromPath', () => { - it("returns all learning objects when a learning path in the database is queried", async () => { + it('returns all learning objects when a learning path in the database is queried', async () => { const result = await learningObjectService.getLearningObjectIdsFromPath(exampleLearningPath); - expect(result).toEqual(exampleLearningPath.nodes.map(it => it.learningObjectHruid)); + expect(result).toEqual(exampleLearningPath.nodes.map((it) => it.learningObjectHruid)); }); - it("also returns all learning object hruids when a learning path from the Dwengo API is queried", async () => { + it('also returns all learning object hruids when a learning path from the Dwengo API is queried', async () => { const result = await learningObjectService.getLearningObjectIdsFromPath(DWENGO_TEST_LEARNING_PATH_ID); expect(new Set(result)).toEqual(DWENGO_TEST_LEARNING_PATH_HRUIDS); }); - it("returns an empty list when queried with a non-existing learning path id", async () => { - const result = await learningObjectService.getLearningObjectIdsFromPath({hruid: "non_existing", language: Language.Dutch}); + it('returns an empty list when queried with a non-existing learning path id', async () => { + const result = await learningObjectService.getLearningObjectIdsFromPath({ hruid: 'non_existing', language: Language.Dutch }); expect(result).toEqual([]); }); }); From a69e2625afae8ac714b3f9eb8cc60907e67b3421 Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Tue, 11 Mar 2025 06:13:29 +0100 Subject: [PATCH 144/180] feat(backend): Added support for customized learning paths to the database learning path provider. --- backend/src/interfaces/learning-content.ts | 1 + .../database-learning-path-provider.ts | 40 +++++++---- .../learning-path-personalization-util.ts | 42 ++++++++++++ .../learning-path-personalizing-service.ts | 68 ------------------- .../learning-paths/learning-path-provider.ts | 3 +- .../learning-paths/learning-path-service.ts | 15 ++-- .../learning-paths/point-of-view.d.ts | 1 - 7 files changed, 84 insertions(+), 86 deletions(-) create mode 100644 backend/src/services/learning-paths/learning-path-personalization-util.ts delete mode 100644 backend/src/services/learning-paths/learning-path-personalizing-service.ts delete mode 100644 backend/src/services/learning-paths/point-of-view.d.ts diff --git a/backend/src/interfaces/learning-content.ts b/backend/src/interfaces/learning-content.ts index 970796a2..a558dd9c 100644 --- a/backend/src/interfaces/learning-content.ts +++ b/backend/src/interfaces/learning-content.ts @@ -26,6 +26,7 @@ export interface LearningObjectNode { transitions: Transition[]; created_at: string; updatedAt: string; + done?: boolean; // true if a submission exists for this node by the user for whom the learning path is customized. } export interface LearningPath { diff --git a/backend/src/services/learning-paths/database-learning-path-provider.ts b/backend/src/services/learning-paths/database-learning-path-provider.ts index 3b3b49af..d804ad64 100644 --- a/backend/src/services/learning-paths/database-learning-path-provider.ts +++ b/backend/src/services/learning-paths/database-learning-path-provider.ts @@ -6,6 +6,11 @@ import { Language } from '../../entities/content/language'; import learningObjectService from '../learning-objects/learning-object-service'; import { LearningPathNode } from '../../entities/content/learning-path-node.entity'; import { LearningPathTransition } from '../../entities/content/learning-path-transition.entity'; +import { + getLastSubmissionForCustomizationTarget, + isTransitionPossible, + PersonalizationTarget +} from "./learning-path-personalization-util"; /** * Fetches the corresponding learning object for each of the nodes and creates a map that maps each node to its @@ -37,7 +42,7 @@ async function getLearningObjectsForNodes(nodes: LearningPathNode[]): Promise { +async function convertLearningPath(learningPath: LearningPathEntity, order: number, personalizedFor?: PersonalizationTarget): Promise { const nodesToLearningObjects: Map = await getLearningObjectsForNodes(learningPath.nodes); const targetAges = nodesToLearningObjects @@ -52,6 +57,8 @@ async function convertLearningPath(learningPath: LearningPathEntity, order: numb const image = learningPath.image ? learningPath.image.toString('base64') : undefined; + const convertedNodes = await convertNodes(nodesToLearningObjects, personalizedFor); + return { _id: `${learningPath.hruid}/${learningPath.language}`, // For backwards compatibility with the original Dwengo API. __order: order, @@ -60,9 +67,9 @@ async function convertLearningPath(learningPath: LearningPathEntity, order: numb description: learningPath.description, image: image, title: learningPath.title, - nodes: convertNodes(nodesToLearningObjects), + nodes: convertedNodes, num_nodes: learningPath.nodes.length, - num_nodes_left: learningPath.nodes.length, // TODO: Adjust when submissions are added. + num_nodes_left: convertedNodes.filter(it => !it.done).length, keywords: keywords.join(' '), target_ages: targetAges, max_age: Math.max(...targetAges), @@ -74,12 +81,14 @@ async function convertLearningPath(learningPath: LearningPathEntity, order: numb * Helper function converting pairs of learning path nodes (as represented in the database) and the corresponding * learning objects into a list of learning path nodes as they should be represented in the API. * @param nodesToLearningObjects + * @param personalizedFor */ -function convertNodes(nodesToLearningObjects: Map): LearningObjectNode[] { - return nodesToLearningObjects +async function convertNodes(nodesToLearningObjects: Map, personalizedFor?: PersonalizationTarget): Promise { + const nodesPromise = nodesToLearningObjects .entries() - .map((entry) => { + .map(async(entry) => { const [node, learningObject] = entry; + const lastSubmission = personalizedFor ? await getLastSubmissionForCustomizationTarget(node, personalizedFor) : null; return { _id: learningObject.uuid, language: learningObject.language, @@ -88,10 +97,13 @@ function convertNodes(nodesToLearningObjects: Map convertTransition(trans, i, nodesToLearningObjects)), + transitions: node.transitions + .filter(trans => !personalizedFor || isTransitionPossible(trans, lastSubmission)) // If we want a personalized learning path, remove all transitions that aren't possible. + .map((trans, i) => convertTransition(trans, i, nodesToLearningObjects)), // then convert all the transition }; }) .toArray(); + return await Promise.all(nodesPromise); } /** @@ -131,12 +143,16 @@ const databaseLearningPathProvider: LearningPathProvider = { /** * Fetch the learning paths with the given hruids from the database. */ - async fetchLearningPaths(hruids: string[], language: Language, source: string): Promise { + async fetchLearningPaths(hruids: string[], language: Language, source: string, personalizedFor?: PersonalizationTarget): Promise { const learningPathRepo = getLearningPathRepository(); - const learningPaths = await Promise.all(hruids.map((hruid) => learningPathRepo.findByHruidAndLanguage(hruid, language))); + const learningPaths = ( + await Promise.all( + hruids.map((hruid) => learningPathRepo.findByHruidAndLanguage(hruid, language)) + ) + ).filter((learningPath) => learningPath !== null); const filteredLearningPaths = await Promise.all( - learningPaths.filter((learningPath) => learningPath !== null).map((learningPath, index) => convertLearningPath(learningPath, index)) + learningPaths.map((learningPath, index) => convertLearningPath(learningPath, index, personalizedFor)) ); return { @@ -149,11 +165,11 @@ const databaseLearningPathProvider: LearningPathProvider = { /** * Search learning paths in the database using the given search string. */ - async searchLearningPaths(query: string, language: Language): Promise { + async searchLearningPaths(query: string, language: Language, personalizedFor?: PersonalizationTarget): Promise { const learningPathRepo = getLearningPathRepository(); const searchResults = await learningPathRepo.findByQueryStringAndLanguage(query, language); - return await Promise.all(searchResults.map((result, index) => convertLearningPath(result, index))); + return await Promise.all(searchResults.map((result, index) => convertLearningPath(result, index, personalizedFor))); }, }; diff --git a/backend/src/services/learning-paths/learning-path-personalization-util.ts b/backend/src/services/learning-paths/learning-path-personalization-util.ts new file mode 100644 index 00000000..9217fa34 --- /dev/null +++ b/backend/src/services/learning-paths/learning-path-personalization-util.ts @@ -0,0 +1,42 @@ +import {LearningPathNode} from "../../entities/content/learning-path-node.entity"; +import {Student} from "../../entities/users/student.entity"; +import {Group} from "../../entities/assignments/group.entity"; +import {Submission} from "../../entities/assignments/submission.entity"; +import {getSubmissionRepository} from "../../data/repositories"; +import {LearningObjectIdentifier} from "../../entities/content/learning-object-identifier"; +import {LearningPathTransition} from "../../entities/content/learning-path-transition.entity"; +import {JSONPath} from "jsonpath-plus"; + +export type PersonalizationTarget = { type: 'student'; student: Student } | { type: 'group'; group: Group }; +/** + * Returns the last submission for the learning object associated with the given node and for the student or group + */ +export async function getLastSubmissionForCustomizationTarget(node: LearningPathNode, pathFor: PersonalizationTarget): Promise { + const submissionRepo = getSubmissionRepository(); + const learningObjectId: LearningObjectIdentifier = { + hruid: node.learningObjectHruid, + language: node.language, + version: node.version, + }; + if (pathFor.type === 'group') { + return await submissionRepo.findMostRecentSubmissionForGroup(learningObjectId, pathFor.group); + } else { + return await submissionRepo.findMostRecentSubmissionForStudent(learningObjectId, pathFor.student); + } +} + + +/** + * Checks whether the condition of the given transaction is fulfilled by the given submission. + * @param transition + * @param submitted + */ +export function isTransitionPossible(transition: LearningPathTransition, submitted: object | null): boolean { + if (transition.condition === 'true' || !transition.condition) { + return true; // If the transition is unconditional, we can go on. + } + if (submitted === null) { + return false; // If the transition is not unconditional and there was no submission, the transition is not possible. + } + return JSONPath({ path: transition.condition, json: submitted }).length === 0; +} diff --git a/backend/src/services/learning-paths/learning-path-personalizing-service.ts b/backend/src/services/learning-paths/learning-path-personalizing-service.ts deleted file mode 100644 index f204d742..00000000 --- a/backend/src/services/learning-paths/learning-path-personalizing-service.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Student } from '../../entities/users/student.entity'; -import { getSubmissionRepository } from '../../data/repositories'; -import { Group } from '../../entities/assignments/group.entity'; -import { Submission } from '../../entities/assignments/submission.entity'; -import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier'; -import { LearningPathNode } from '../../entities/content/learning-path-node.entity'; -import { LearningPathTransition } from '../../entities/content/learning-path-transition.entity'; -import { JSONPath } from 'jsonpath-plus'; - -/** - * Returns the last submission for the learning object associated with the given node and for the student or group - */ -async function getLastRelevantSubmission(node: LearningPathNode, pathFor: { student?: Student; group?: Group }): Promise { - const submissionRepo = getSubmissionRepository(); - const learningObjectId: LearningObjectIdentifier = { - hruid: node.learningObjectHruid, - language: node.language, - version: node.version, - }; - let lastSubmission: Submission | null; - if (pathFor.group) { - lastSubmission = await submissionRepo.findMostRecentSubmissionForGroup(learningObjectId, pathFor.group); - } else if (pathFor.student) { - lastSubmission = await submissionRepo.findMostRecentSubmissionForStudent(learningObjectId, pathFor.student); - } else { - throw new Error('The path must either be created for a certain group or for a certain student!'); - } - return lastSubmission; -} - -function transitionPossible(transition: LearningPathTransition, submitted: object | null): boolean { - if (transition.condition === 'true' || !transition.condition) { - return true; // If the transition is unconditional, we can go on. - } - if (submitted === null) { - return false; // If the transition is not unconditional and there was no submission, the transition is not possible. - } - return JSONPath({ path: transition.condition, json: submitted }).length === 0; -} - -/** - * Service to create individual trajectories from learning paths based on the submissions of the student or group. - */ -const learningPathPersonalizingService = { - async calculatePersonalizedTrajectory(nodes: LearningPathNode[], pathFor: { student?: Student; group?: Group }): Promise { - const trajectory: LearningPathNode[] = []; - - // Always start with the start node. - let currentNode = nodes.filter((it) => it.startNode)[0]; - trajectory.push(currentNode); - - while (true) { - // At every node, calculate all the possible next transitions. - const lastSubmission = await getLastRelevantSubmission(currentNode, pathFor); - const submitted = lastSubmission === null ? null : JSON.parse(lastSubmission.content); - const possibleTransitions = currentNode.transitions.filter((it) => transitionPossible(it, submitted)); - - if (possibleTransitions.length === 0) { - // If there are none, the trajectory has ended. - return trajectory; - } // Otherwise, take the first possible transition. - currentNode = possibleTransitions[0].node; - trajectory.push(currentNode); - } - }, -}; - -export default learningPathPersonalizingService; diff --git a/backend/src/services/learning-paths/learning-path-provider.ts b/backend/src/services/learning-paths/learning-path-provider.ts index baff35bf..571c231a 100644 --- a/backend/src/services/learning-paths/learning-path-provider.ts +++ b/backend/src/services/learning-paths/learning-path-provider.ts @@ -1,5 +1,6 @@ import { LearningPath, LearningPathResponse } from '../../interfaces/learning-content'; import { Language } from '../../entities/content/language'; +import {PersonalizationTarget} from "./learning-path-personalizing-service"; /** * Generic interface for a service which provides access to learning paths from a data source. @@ -8,7 +9,7 @@ export interface LearningPathProvider { /** * Fetch the learning paths with the given hruids from the data source. */ - fetchLearningPaths(hruids: string[], language: Language, source: string): Promise; + fetchLearningPaths(hruids: string[], language: Language, source: string, personalizedFor?: PersonalizationTarget): Promise; /** * Search learning paths in the data source using the given search string. diff --git a/backend/src/services/learning-paths/learning-path-service.ts b/backend/src/services/learning-paths/learning-path-service.ts index 23f0d9ba..c204872c 100644 --- a/backend/src/services/learning-paths/learning-path-service.ts +++ b/backend/src/services/learning-paths/learning-path-service.ts @@ -3,6 +3,7 @@ import dwengoApiLearningPathProvider from './dwengo-api-learning-path-provider'; import databaseLearningPathProvider from './database-learning-path-provider'; import { EnvVars, getEnvVar } from '../../util/envvars'; import { Language } from '../../entities/content/language'; +import {PersonalizationTarget} from "./learning-path-personalizing-service"; const userContentPrefix = getEnvVar(EnvVars.UserContentPrefix); const allProviders = [dwengoApiLearningPathProvider, databaseLearningPathProvider]; @@ -13,16 +14,22 @@ const allProviders = [dwengoApiLearningPathProvider, databaseLearningPathProvide const learningPathService = { /** * Fetch the learning paths with the given hruids from the data source. + * @param hruids For each of the hruids, the learning path will be fetched. + * @param language This is the language each of the learning paths will use. + * @param source + * @param personalizedFor If this is set, a learning path personalized for the given group or student will be returned. */ - async fetchLearningPaths(hruids: string[], language: Language, source: string): Promise { + async fetchLearningPaths(hruids: string[], language: Language, source: string, personalizedFor?: PersonalizationTarget): Promise { const userContentHruids = hruids.filter((hruid) => hruid.startsWith(userContentPrefix)); const nonUserContentHruids = hruids.filter((hruid) => !hruid.startsWith(userContentPrefix)); - const userContentLearningPaths = await databaseLearningPathProvider.fetchLearningPaths(userContentHruids, language, source); - const nonUserContentLearningPaths = await dwengoApiLearningPathProvider.fetchLearningPaths(nonUserContentHruids, language, source); + const userContentLearningPaths = await databaseLearningPathProvider.fetchLearningPaths(userContentHruids, language, source, personalizedFor); + const nonUserContentLearningPaths = await dwengoApiLearningPathProvider.fetchLearningPaths(nonUserContentHruids, language, source, personalizedFor); + + let result = (userContentLearningPaths.data || []).concat(nonUserContentLearningPaths.data || []); return { - data: (userContentLearningPaths.data || []).concat(nonUserContentLearningPaths.data || []), + data: result, source: source, success: userContentLearningPaths.success || nonUserContentLearningPaths.success, }; diff --git a/backend/src/services/learning-paths/point-of-view.d.ts b/backend/src/services/learning-paths/point-of-view.d.ts deleted file mode 100644 index 14190090..00000000 --- a/backend/src/services/learning-paths/point-of-view.d.ts +++ /dev/null @@ -1 +0,0 @@ -type PointOfView = { type: 'student'; student: Student } | { type: 'group'; group: Group }; From bdbfe380bedf4dd97166a7425fe17dd9250aaa9a Mon Sep 17 00:00:00 2001 From: Lint Action Date: Tue, 11 Mar 2025 05:14:04 +0000 Subject: [PATCH 145/180] style: fix linting issues met ESLint --- backend/src/interfaces/learning-content.ts | 2 +- .../learning-paths/database-learning-path-provider.ts | 2 +- .../learning-paths/learning-path-personalization-util.ts | 4 ++-- backend/src/services/learning-paths/learning-path-service.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/src/interfaces/learning-content.ts b/backend/src/interfaces/learning-content.ts index a558dd9c..997865ef 100644 --- a/backend/src/interfaces/learning-content.ts +++ b/backend/src/interfaces/learning-content.ts @@ -26,7 +26,7 @@ export interface LearningObjectNode { transitions: Transition[]; created_at: string; updatedAt: string; - done?: boolean; // true if a submission exists for this node by the user for whom the learning path is customized. + done?: boolean; // True if a submission exists for this node by the user for whom the learning path is customized. } export interface LearningPath { diff --git a/backend/src/services/learning-paths/database-learning-path-provider.ts b/backend/src/services/learning-paths/database-learning-path-provider.ts index d804ad64..2a784daf 100644 --- a/backend/src/services/learning-paths/database-learning-path-provider.ts +++ b/backend/src/services/learning-paths/database-learning-path-provider.ts @@ -99,7 +99,7 @@ async function convertNodes(nodesToLearningObjects: Map !personalizedFor || isTransitionPossible(trans, lastSubmission)) // If we want a personalized learning path, remove all transitions that aren't possible. - .map((trans, i) => convertTransition(trans, i, nodesToLearningObjects)), // then convert all the transition + .map((trans, i) => convertTransition(trans, i, nodesToLearningObjects)), // Then convert all the transition }; }) .toArray(); diff --git a/backend/src/services/learning-paths/learning-path-personalization-util.ts b/backend/src/services/learning-paths/learning-path-personalization-util.ts index 9217fa34..df268735 100644 --- a/backend/src/services/learning-paths/learning-path-personalization-util.ts +++ b/backend/src/services/learning-paths/learning-path-personalization-util.ts @@ -20,9 +20,9 @@ export async function getLastSubmissionForCustomizationTarget(node: LearningPath }; if (pathFor.type === 'group') { return await submissionRepo.findMostRecentSubmissionForGroup(learningObjectId, pathFor.group); - } else { + } return await submissionRepo.findMostRecentSubmissionForStudent(learningObjectId, pathFor.student); - } + } diff --git a/backend/src/services/learning-paths/learning-path-service.ts b/backend/src/services/learning-paths/learning-path-service.ts index c204872c..f2372672 100644 --- a/backend/src/services/learning-paths/learning-path-service.ts +++ b/backend/src/services/learning-paths/learning-path-service.ts @@ -26,7 +26,7 @@ const learningPathService = { const userContentLearningPaths = await databaseLearningPathProvider.fetchLearningPaths(userContentHruids, language, source, personalizedFor); const nonUserContentLearningPaths = await dwengoApiLearningPathProvider.fetchLearningPaths(nonUserContentHruids, language, source, personalizedFor); - let result = (userContentLearningPaths.data || []).concat(nonUserContentLearningPaths.data || []); + const result = (userContentLearningPaths.data || []).concat(nonUserContentLearningPaths.data || []); return { data: result, From 6624dacabda649bedee8a9796d5ab203d27c21d8 Mon Sep 17 00:00:00 2001 From: Lint Action Date: Tue, 11 Mar 2025 05:14:08 +0000 Subject: [PATCH 146/180] style: fix linting issues met Prettier --- .../database-learning-path-provider.ts | 32 ++++++++++--------- .../learning-path-personalization-util.ts | 22 ++++++------- .../learning-paths/learning-path-provider.ts | 2 +- .../learning-paths/learning-path-service.ts | 16 ++++++++-- 4 files changed, 41 insertions(+), 31 deletions(-) diff --git a/backend/src/services/learning-paths/database-learning-path-provider.ts b/backend/src/services/learning-paths/database-learning-path-provider.ts index 2a784daf..36ab58a9 100644 --- a/backend/src/services/learning-paths/database-learning-path-provider.ts +++ b/backend/src/services/learning-paths/database-learning-path-provider.ts @@ -6,11 +6,7 @@ import { Language } from '../../entities/content/language'; import learningObjectService from '../learning-objects/learning-object-service'; import { LearningPathNode } from '../../entities/content/learning-path-node.entity'; import { LearningPathTransition } from '../../entities/content/learning-path-transition.entity'; -import { - getLastSubmissionForCustomizationTarget, - isTransitionPossible, - PersonalizationTarget -} from "./learning-path-personalization-util"; +import { getLastSubmissionForCustomizationTarget, isTransitionPossible, PersonalizationTarget } from './learning-path-personalization-util'; /** * Fetches the corresponding learning object for each of the nodes and creates a map that maps each node to its @@ -69,7 +65,7 @@ async function convertLearningPath(learningPath: LearningPathEntity, order: numb title: learningPath.title, nodes: convertedNodes, num_nodes: learningPath.nodes.length, - num_nodes_left: convertedNodes.filter(it => !it.done).length, + num_nodes_left: convertedNodes.filter((it) => !it.done).length, keywords: keywords.join(' '), target_ages: targetAges, max_age: Math.max(...targetAges), @@ -83,10 +79,13 @@ async function convertLearningPath(learningPath: LearningPathEntity, order: numb * @param nodesToLearningObjects * @param personalizedFor */ -async function convertNodes(nodesToLearningObjects: Map, personalizedFor?: PersonalizationTarget): Promise { +async function convertNodes( + nodesToLearningObjects: Map, + personalizedFor?: PersonalizationTarget +): Promise { const nodesPromise = nodesToLearningObjects .entries() - .map(async(entry) => { + .map(async (entry) => { const [node, learningObject] = entry; const lastSubmission = personalizedFor ? await getLastSubmissionForCustomizationTarget(node, personalizedFor) : null; return { @@ -98,7 +97,7 @@ async function convertNodes(nodesToLearningObjects: Map !personalizedFor || isTransitionPossible(trans, lastSubmission)) // If we want a personalized learning path, remove all transitions that aren't possible. + .filter((trans) => !personalizedFor || isTransitionPossible(trans, lastSubmission)) // If we want a personalized learning path, remove all transitions that aren't possible. .map((trans, i) => convertTransition(trans, i, nodesToLearningObjects)), // Then convert all the transition }; }) @@ -143,14 +142,17 @@ const databaseLearningPathProvider: LearningPathProvider = { /** * Fetch the learning paths with the given hruids from the database. */ - async fetchLearningPaths(hruids: string[], language: Language, source: string, personalizedFor?: PersonalizationTarget): Promise { + async fetchLearningPaths( + hruids: string[], + language: Language, + source: string, + personalizedFor?: PersonalizationTarget + ): Promise { const learningPathRepo = getLearningPathRepository(); - const learningPaths = ( - await Promise.all( - hruids.map((hruid) => learningPathRepo.findByHruidAndLanguage(hruid, language)) - ) - ).filter((learningPath) => learningPath !== null); + const learningPaths = (await Promise.all(hruids.map((hruid) => learningPathRepo.findByHruidAndLanguage(hruid, language)))).filter( + (learningPath) => learningPath !== null + ); const filteredLearningPaths = await Promise.all( learningPaths.map((learningPath, index) => convertLearningPath(learningPath, index, personalizedFor)) ); diff --git a/backend/src/services/learning-paths/learning-path-personalization-util.ts b/backend/src/services/learning-paths/learning-path-personalization-util.ts index df268735..533ef15c 100644 --- a/backend/src/services/learning-paths/learning-path-personalization-util.ts +++ b/backend/src/services/learning-paths/learning-path-personalization-util.ts @@ -1,11 +1,11 @@ -import {LearningPathNode} from "../../entities/content/learning-path-node.entity"; -import {Student} from "../../entities/users/student.entity"; -import {Group} from "../../entities/assignments/group.entity"; -import {Submission} from "../../entities/assignments/submission.entity"; -import {getSubmissionRepository} from "../../data/repositories"; -import {LearningObjectIdentifier} from "../../entities/content/learning-object-identifier"; -import {LearningPathTransition} from "../../entities/content/learning-path-transition.entity"; -import {JSONPath} from "jsonpath-plus"; +import { LearningPathNode } from '../../entities/content/learning-path-node.entity'; +import { Student } from '../../entities/users/student.entity'; +import { Group } from '../../entities/assignments/group.entity'; +import { Submission } from '../../entities/assignments/submission.entity'; +import { getSubmissionRepository } from '../../data/repositories'; +import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier'; +import { LearningPathTransition } from '../../entities/content/learning-path-transition.entity'; +import { JSONPath } from 'jsonpath-plus'; export type PersonalizationTarget = { type: 'student'; student: Student } | { type: 'group'; group: Group }; /** @@ -20,12 +20,10 @@ export async function getLastSubmissionForCustomizationTarget(node: LearningPath }; if (pathFor.type === 'group') { return await submissionRepo.findMostRecentSubmissionForGroup(learningObjectId, pathFor.group); - } - return await submissionRepo.findMostRecentSubmissionForStudent(learningObjectId, pathFor.student); - + } + return await submissionRepo.findMostRecentSubmissionForStudent(learningObjectId, pathFor.student); } - /** * Checks whether the condition of the given transaction is fulfilled by the given submission. * @param transition diff --git a/backend/src/services/learning-paths/learning-path-provider.ts b/backend/src/services/learning-paths/learning-path-provider.ts index 571c231a..8736df21 100644 --- a/backend/src/services/learning-paths/learning-path-provider.ts +++ b/backend/src/services/learning-paths/learning-path-provider.ts @@ -1,6 +1,6 @@ import { LearningPath, LearningPathResponse } from '../../interfaces/learning-content'; import { Language } from '../../entities/content/language'; -import {PersonalizationTarget} from "./learning-path-personalizing-service"; +import { PersonalizationTarget } from './learning-path-personalizing-service'; /** * Generic interface for a service which provides access to learning paths from a data source. diff --git a/backend/src/services/learning-paths/learning-path-service.ts b/backend/src/services/learning-paths/learning-path-service.ts index f2372672..b7c7e794 100644 --- a/backend/src/services/learning-paths/learning-path-service.ts +++ b/backend/src/services/learning-paths/learning-path-service.ts @@ -3,7 +3,7 @@ import dwengoApiLearningPathProvider from './dwengo-api-learning-path-provider'; import databaseLearningPathProvider from './database-learning-path-provider'; import { EnvVars, getEnvVar } from '../../util/envvars'; import { Language } from '../../entities/content/language'; -import {PersonalizationTarget} from "./learning-path-personalizing-service"; +import { PersonalizationTarget } from './learning-path-personalizing-service'; const userContentPrefix = getEnvVar(EnvVars.UserContentPrefix); const allProviders = [dwengoApiLearningPathProvider, databaseLearningPathProvider]; @@ -19,12 +19,22 @@ const learningPathService = { * @param source * @param personalizedFor If this is set, a learning path personalized for the given group or student will be returned. */ - async fetchLearningPaths(hruids: string[], language: Language, source: string, personalizedFor?: PersonalizationTarget): Promise { + async fetchLearningPaths( + hruids: string[], + language: Language, + source: string, + personalizedFor?: PersonalizationTarget + ): Promise { const userContentHruids = hruids.filter((hruid) => hruid.startsWith(userContentPrefix)); const nonUserContentHruids = hruids.filter((hruid) => !hruid.startsWith(userContentPrefix)); const userContentLearningPaths = await databaseLearningPathProvider.fetchLearningPaths(userContentHruids, language, source, personalizedFor); - const nonUserContentLearningPaths = await dwengoApiLearningPathProvider.fetchLearningPaths(nonUserContentHruids, language, source, personalizedFor); + const nonUserContentLearningPaths = await dwengoApiLearningPathProvider.fetchLearningPaths( + nonUserContentHruids, + language, + source, + personalizedFor + ); const result = (userContentLearningPaths.data || []).concat(nonUserContentLearningPaths.data || []); From 64581505ef7954df4756029a76bc23cd86070601 Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Tue, 11 Mar 2025 06:17:16 +0100 Subject: [PATCH 147/180] fix(backend): Resten van oude implementaties verwijderd --- .../src/services/learning-paths/learning-path-provider.ts | 4 ++-- .../src/services/learning-paths/learning-path-service.ts | 6 +++--- backend/src/services/learningObjects.ts | 0 backend/src/services/learningPaths.ts | 0 4 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 backend/src/services/learningObjects.ts delete mode 100644 backend/src/services/learningPaths.ts diff --git a/backend/src/services/learning-paths/learning-path-provider.ts b/backend/src/services/learning-paths/learning-path-provider.ts index 571c231a..137b4678 100644 --- a/backend/src/services/learning-paths/learning-path-provider.ts +++ b/backend/src/services/learning-paths/learning-path-provider.ts @@ -1,6 +1,6 @@ import { LearningPath, LearningPathResponse } from '../../interfaces/learning-content'; import { Language } from '../../entities/content/language'; -import {PersonalizationTarget} from "./learning-path-personalizing-service"; +import {PersonalizationTarget} from "./learning-path-personalization-util"; /** * Generic interface for a service which provides access to learning paths from a data source. @@ -14,5 +14,5 @@ export interface LearningPathProvider { /** * Search learning paths in the data source using the given search string. */ - searchLearningPaths(query: string, language: Language): Promise; + searchLearningPaths(query: string, language: Language, personalizedFor?: PersonalizationTarget): Promise; } diff --git a/backend/src/services/learning-paths/learning-path-service.ts b/backend/src/services/learning-paths/learning-path-service.ts index c204872c..d6662eff 100644 --- a/backend/src/services/learning-paths/learning-path-service.ts +++ b/backend/src/services/learning-paths/learning-path-service.ts @@ -3,7 +3,7 @@ import dwengoApiLearningPathProvider from './dwengo-api-learning-path-provider'; import databaseLearningPathProvider from './database-learning-path-provider'; import { EnvVars, getEnvVar } from '../../util/envvars'; import { Language } from '../../entities/content/language'; -import {PersonalizationTarget} from "./learning-path-personalizing-service"; +import {PersonalizationTarget} from "./learning-path-personalization-util"; const userContentPrefix = getEnvVar(EnvVars.UserContentPrefix); const allProviders = [dwengoApiLearningPathProvider, databaseLearningPathProvider]; @@ -38,8 +38,8 @@ const learningPathService = { /** * Search learning paths in the data source using the given search string. */ - async searchLearningPaths(query: string, language: Language): Promise { - const providerResponses = await Promise.all(allProviders.map((provider) => provider.searchLearningPaths(query, language))); + async searchLearningPaths(query: string, language: Language, personalizedFor?: PersonalizationTarget): Promise { + const providerResponses = await Promise.all(allProviders.map((provider) => provider.searchLearningPaths(query, language, personalizedFor))); return providerResponses.flat(); }, }; diff --git a/backend/src/services/learningObjects.ts b/backend/src/services/learningObjects.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/backend/src/services/learningPaths.ts b/backend/src/services/learningPaths.ts deleted file mode 100644 index e69de29b..00000000 From 009d7b803c34fdb964e9dc666191000e319f1019 Mon Sep 17 00:00:00 2001 From: Lint Action Date: Tue, 11 Mar 2025 05:19:33 +0000 Subject: [PATCH 148/180] style: fix linting issues met Prettier --- backend/src/services/learning-paths/learning-path-provider.ts | 2 +- backend/src/services/learning-paths/learning-path-service.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/services/learning-paths/learning-path-provider.ts b/backend/src/services/learning-paths/learning-path-provider.ts index 137b4678..4c8b9f21 100644 --- a/backend/src/services/learning-paths/learning-path-provider.ts +++ b/backend/src/services/learning-paths/learning-path-provider.ts @@ -1,6 +1,6 @@ import { LearningPath, LearningPathResponse } from '../../interfaces/learning-content'; import { Language } from '../../entities/content/language'; -import {PersonalizationTarget} from "./learning-path-personalization-util"; +import { PersonalizationTarget } from './learning-path-personalization-util'; /** * Generic interface for a service which provides access to learning paths from a data source. diff --git a/backend/src/services/learning-paths/learning-path-service.ts b/backend/src/services/learning-paths/learning-path-service.ts index 92a04b1a..9fb6f875 100644 --- a/backend/src/services/learning-paths/learning-path-service.ts +++ b/backend/src/services/learning-paths/learning-path-service.ts @@ -3,7 +3,7 @@ import dwengoApiLearningPathProvider from './dwengo-api-learning-path-provider'; import databaseLearningPathProvider from './database-learning-path-provider'; import { EnvVars, getEnvVar } from '../../util/envvars'; import { Language } from '../../entities/content/language'; -import {PersonalizationTarget} from "./learning-path-personalization-util"; +import { PersonalizationTarget } from './learning-path-personalization-util'; const userContentPrefix = getEnvVar(EnvVars.UserContentPrefix); const allProviders = [dwengoApiLearningPathProvider, databaseLearningPathProvider]; From fc46e79d05162a62cedcb8ac5ec1868adc93d8e0 Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Tue, 11 Mar 2025 11:58:55 +0100 Subject: [PATCH 149/180] fix(backend): Fouten in isTransitionPossible en het opzetten van de testdata verbeterd. --- .../entities/assignments/submission.entity.ts | 4 +- .../content/learning-object.entity.ts | 6 +- .../database-learning-path-provider.ts | 16 +- .../learning-path-personalization-util.ts | 3 +- .../database-learning-path-provider.test.ts | 138 +++++++++++++++++- .../dummy/dummy-learning-object-example.ts | 7 +- .../test-essay/test-essay-example.ts | 4 + .../test-multiple-choice-example.ts | 4 + .../learning-paths/test-conditions-example.ts | 134 +++++++++-------- backend/vitest.config.ts | 1 + 10 files changed, 249 insertions(+), 68 deletions(-) diff --git a/backend/src/entities/assignments/submission.entity.ts b/backend/src/entities/assignments/submission.entity.ts index 34e0c1f6..920f0a71 100644 --- a/backend/src/entities/assignments/submission.entity.ts +++ b/backend/src/entities/assignments/submission.entity.ts @@ -15,8 +15,8 @@ export class Submission { }) learningObjectLanguage!: Language; - @PrimaryKey({ type: 'string' }) - learningObjectVersion: string = '1'; + @PrimaryKey({ type: 'numeric' }) + learningObjectVersion: number = 1; @PrimaryKey({ type: 'integer' }) submissionNumber!: number; diff --git a/backend/src/entities/content/learning-object.entity.ts b/backend/src/entities/content/learning-object.entity.ts index 55c4a808..c32efedc 100644 --- a/backend/src/entities/content/learning-object.entity.ts +++ b/backend/src/entities/content/learning-object.entity.ts @@ -47,7 +47,7 @@ export class LearningObject { teacherExclusive: boolean = false; @Property({ type: 'array' }) - skosConcepts!: string[]; + skosConcepts: string[] = []; @Embedded({ entity: () => EducationalGoal, @@ -64,8 +64,8 @@ export class LearningObject { @Property({ type: 'smallint', nullable: true }) difficulty?: number; - @Property({ type: 'integer' }) - estimatedTime!: number; + @Property({ type: 'integer', nullable: true }) + estimatedTime?: number; @Embedded({ entity: () => ReturnValue, diff --git a/backend/src/services/learning-paths/database-learning-path-provider.ts b/backend/src/services/learning-paths/database-learning-path-provider.ts index 36ab58a9..925f9f6b 100644 --- a/backend/src/services/learning-paths/database-learning-path-provider.ts +++ b/backend/src/services/learning-paths/database-learning-path-provider.ts @@ -97,14 +97,26 @@ async function convertNodes( learningobject_hruid: node.learningObjectHruid, version: learningObject.version, transitions: node.transitions - .filter((trans) => !personalizedFor || isTransitionPossible(trans, lastSubmission)) // If we want a personalized learning path, remove all transitions that aren't possible. - .map((trans, i) => convertTransition(trans, i, nodesToLearningObjects)), // Then convert all the transition + .filter((trans) => + !personalizedFor || isTransitionPossible(trans, optionalJsonStringToObject(lastSubmission?.content)) // If we want a personalized learning path, remove all transitions that aren't possible. + ).map((trans, i) => convertTransition(trans, i, nodesToLearningObjects)), // Then convert all the transition }; }) .toArray(); return await Promise.all(nodesPromise); } +/** + * Helper method to convert a json string to an object, or null if it is undefined. + */ +function optionalJsonStringToObject(jsonString?: string): object | null { + if (!jsonString) { + return null; + } else { + return JSON.parse(jsonString); + } +} + /** * Helper function which converts a transition in the database representation to a transition in the representation * the Dwengo API uses. diff --git a/backend/src/services/learning-paths/learning-path-personalization-util.ts b/backend/src/services/learning-paths/learning-path-personalization-util.ts index 533ef15c..648b7abc 100644 --- a/backend/src/services/learning-paths/learning-path-personalization-util.ts +++ b/backend/src/services/learning-paths/learning-path-personalization-util.ts @@ -36,5 +36,6 @@ export function isTransitionPossible(transition: LearningPathTransition, submitt if (submitted === null) { return false; // If the transition is not unconditional and there was no submission, the transition is not possible. } - return JSONPath({ path: transition.condition, json: submitted }).length === 0; + const match = JSONPath({ path: transition.condition, json: {submission: submitted} }) + return match.length === 1; } diff --git a/backend/tests/services/learning-path/database-learning-path-provider.test.ts b/backend/tests/services/learning-path/database-learning-path-provider.test.ts index df49ae3b..81d4a149 100644 --- a/backend/tests/services/learning-path/database-learning-path-provider.test.ts +++ b/backend/tests/services/learning-path/database-learning-path-provider.test.ts @@ -2,7 +2,11 @@ import { beforeAll, describe, expect, it } from 'vitest'; import { LearningObject } from '../../../src/entities/content/learning-object.entity'; import { setupTestApp } from '../../setup-tests'; import { LearningPath } from '../../../src/entities/content/learning-path.entity'; -import { getLearningObjectRepository, getLearningPathRepository } from '../../../src/data/repositories'; +import { + getLearningObjectRepository, + getLearningPathRepository, + getStudentRepository, getSubmissionRepository +} from '../../../src/data/repositories'; import learningObjectExample from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example'; import learningPathExample from '../../test-assets/learning-paths/pn-werking-example'; import databaseLearningPathProvider from '../../../src/services/learning-paths/database-learning-path-provider'; @@ -10,6 +14,12 @@ import { expectToBeCorrectLearningPath } from '../../test-utils/expectations'; import { LearningObjectRepository } from '../../../src/data/content/learning-object-repository'; import learningObjectService from '../../../src/services/learning-objects/learning-object-service'; import { Language } from '../../../src/entities/content/language'; +import { + ConditionTestLearningPathAndLearningObjects, + createConditionTestLearningPathAndLearningObjects +} from "../../test-assets/learning-paths/test-conditions-example"; +import {Student} from "../../../src/entities/users/student.entity"; +import {LearningObjectNode, LearningPathResponse} from "../../../src/interfaces/learning-content"; async function initExampleData(): Promise<{ learningObject: LearningObject; learningPath: LearningPath }> { const learningObjectRepo = getLearningObjectRepository(); @@ -21,13 +31,85 @@ async function initExampleData(): Promise<{ learningObject: LearningObject; lear return { learningObject, learningPath }; } +async function initPersonalizationTestData(): Promise<{ + learningContent: ConditionTestLearningPathAndLearningObjects, + studentA: Student, + studentB: Student +}> { + const studentRepo = getStudentRepository(); + const submissionRepo = getSubmissionRepository(); + const learningPathRepo = getLearningPathRepository(); + const learningObjectRepo = getLearningObjectRepository(); + const learningContent = createConditionTestLearningPathAndLearningObjects(); + await learningObjectRepo.save(learningContent.branchingObject); + await learningObjectRepo.save(learningContent.finalObject); + await learningObjectRepo.save(learningContent.extraExerciseObject); + await learningPathRepo.save(learningContent.learningPath); + + console.log(await getSubmissionRepository().findAll({})); + + const studentA = studentRepo.create({ + username: "student_a", + firstName: "Aron", + lastName: "Student" + }); + await studentRepo.save(studentA); + const submissionA = submissionRepo.create({ + learningObjectHruid: learningContent.branchingObject.hruid, + learningObjectLanguage: learningContent.branchingObject.language, + learningObjectVersion: learningContent.branchingObject.version, + submissionNumber: 0, + submitter: studentA, + submissionTime: new Date(), + content: '[0]' + }); + await submissionRepo.save(submissionA); + + const studentB = studentRepo.create({ + username: "student_b", + firstName: "Bill", + lastName: "Student" + }); + await studentRepo.save(studentB); + const submissionB = submissionRepo.create({ + learningObjectHruid: learningContent.branchingObject.hruid, + learningObjectLanguage: learningContent.branchingObject.language, + learningObjectVersion: learningContent.branchingObject.version, + submissionNumber: 1, + submitter: studentB, + submissionTime: new Date(), + content: '[1]' + }); + await submissionRepo.save(submissionB); + + return { + learningContent: learningContent, + studentA: studentA, + studentB: studentB, + } +} + +function expectBranchingObjectNode(result: LearningPathResponse, persTestData: { + learningContent: ConditionTestLearningPathAndLearningObjects; + studentA: Student; + studentB: Student +}): LearningObjectNode { + let branchingObjectMatches = result.data![0].nodes.filter( + it => it.learningobject_hruid === persTestData.learningContent.branchingObject.hruid + ); + expect(branchingObjectMatches.length).toBe(1); + return branchingObjectMatches[0]; +} + describe('DatabaseLearningPathProvider', () => { let learningObjectRepo: LearningObjectRepository; let example: { learningObject: LearningObject; learningPath: LearningPath }; + let persTestData: { learningContent: ConditionTestLearningPathAndLearningObjects, studentA: Student, studentB: Student } beforeAll(async () => { await setupTestApp(); example = await initExampleData(); + persTestData = await initPersonalizationTestData(); learningObjectRepo = getLearningObjectRepository(); }); @@ -55,6 +137,60 @@ describe('DatabaseLearningPathProvider', () => { expectToBeCorrectLearningPath(result.data![0], example.learningPath, learningObjectsOnPath); }); + it("returns the correct personalized learning path", async () => { + // For student A: + let result = await databaseLearningPathProvider.fetchLearningPaths( + [persTestData.learningContent.learningPath.hruid], + persTestData.learningContent.learningPath.language, + 'the source', + {type: 'student', student: persTestData.studentA} + ); + expect(result.success).toBeTruthy(); + expect(result.data?.length).toBe(1); + + // There should be exactly one branching object + let branchingObject = expectBranchingObjectNode(result, persTestData); + + expect( + branchingObject + .transitions + .filter(it => it.next.hruid === persTestData.learningContent.finalObject.hruid) + .length + ).toBe(0); // studentA picked the first option, therefore, there should be no direct path to the final object. + expect( + branchingObject + .transitions + .filter(it => it.next.hruid === persTestData.learningContent.extraExerciseObject.hruid) + .length + ).toBe(1); // There should however be a path to the extra exercise object. + + // For student B: + result = await databaseLearningPathProvider.fetchLearningPaths( + [persTestData.learningContent.learningPath.hruid], + persTestData.learningContent.learningPath.language, + 'the source', + {type: 'student', student: persTestData.studentB} + ); + expect(result.success).toBeTruthy(); + expect(result.data?.length).toBe(1); + + // There should still be exactly one branching object + branchingObject = expectBranchingObjectNode(result, persTestData); + + // However, now the student picks the other option. + expect( + branchingObject + .transitions + .filter(it => it.next.hruid === persTestData.learningContent.finalObject.hruid) + .length + ).toBe(1); // studentB picked the second option, therefore, there should be a direct path to the final object. + expect( + branchingObject + .transitions + .filter(it => it.next.hruid === persTestData.learningContent.extraExerciseObject.hruid) + .length + ).toBe(0); // There should not be a path anymore to the extra exercise object. + }); it('returns a non-successful response if a non-existing learning path is queried', async () => { const result = await databaseLearningPathProvider.fetchLearningPaths( [example.learningPath.hruid], diff --git a/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts b/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts index 6dbe54b0..14f62828 100644 --- a/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts +++ b/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts @@ -3,6 +3,7 @@ import { LearningObject } from '../../../../src/entities/content/learning-object import { Language } from '../../../../src/entities/content/language'; import { loadTestAsset } from '../../../test-utils/load-test-asset'; import { DwengoContentType } from '../../../../src/services/learning-objects/processing/content-type'; +import {EnvVars, getEnvVar} from "../../../../src/util/envvars"; /** * Create a dummy learning object to be used in tests where multiple learning objects are needed (for example for use @@ -12,13 +13,17 @@ export function dummyLearningObject(hruid: string, language: Language, title: st return { createLearningObject: () => { const learningObject = new LearningObject(); - learningObject.hruid = hruid; + learningObject.hruid = getEnvVar(EnvVars.UserContentPrefix) + hruid; learningObject.language = language; learningObject.version = 1; learningObject.title = title; learningObject.description = 'Just a dummy learning object for testing purposes'; learningObject.contentType = DwengoContentType.TEXT_PLAIN; learningObject.content = Buffer.from('Dummy content'); + learningObject.returnValue = { + callbackUrl: `/learningObject/${hruid}/submissions`, + callbackSchema: "[]" + } return learningObject; }, createAttachment: {}, diff --git a/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts b/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts index b1ff330e..c0c18c6a 100644 --- a/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts +++ b/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts @@ -14,6 +14,10 @@ const example: LearningObjectExample = { learningObject.title = 'Essay question for testing'; learningObject.description = 'This essay question was only created for testing purposes.'; learningObject.contentType = DwengoContentType.GIFT; + learningObject.returnValue = { + callbackUrl: `/learningObject/${learningObject.hruid}/submissions`, + callbackSchema: '["antwoord vraag 1"]' + } learningObject.content = loadTestAsset('learning-objects/test-essay/content.txt'); return learningObject; }, diff --git a/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts b/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts index cfb0b5a2..c5dcdc94 100644 --- a/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts +++ b/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts @@ -14,6 +14,10 @@ const example: LearningObjectExample = { learningObject.title = 'Multiple choice question for testing'; learningObject.description = 'This multiple choice question was only created for testing purposes.'; learningObject.contentType = DwengoContentType.GIFT; + learningObject.returnValue = { + callbackUrl: `/learningObject/${learningObject.hruid}/submissions`, + callbackSchema: '["antwoord vraag 1"]' + } learningObject.content = loadTestAsset('learning-objects/test-multiple-choice/content.txt'); return learningObject; }, diff --git a/backend/tests/test-assets/learning-paths/test-conditions-example.ts b/backend/tests/test-assets/learning-paths/test-conditions-example.ts index b6cf3e9d..f06ff904 100644 --- a/backend/tests/test-assets/learning-paths/test-conditions-example.ts +++ b/backend/tests/test-assets/learning-paths/test-conditions-example.ts @@ -3,66 +3,84 @@ import { Language } from '../../../src/entities/content/language'; import testMultipleChoiceExample from '../learning-objects/test-multiple-choice/test-multiple-choice-example'; import { dummyLearningObject } from '../learning-objects/dummy/dummy-learning-object-example'; import { createLearningPathNode, createLearningPathTransition } from './learning-path-utils'; +import {LearningObject} from "../../../src/entities/content/learning-object.entity"; +import {EnvVars, getEnvVar} from "../../../src/util/envvars"; + +export type ConditionTestLearningPathAndLearningObjects = { + branchingObject: LearningObject, + extraExerciseObject: LearningObject, + finalObject: LearningObject, + learningPath: LearningPath +}; + +export function createConditionTestLearningPathAndLearningObjects(){ + const learningPath = new LearningPath(); + learningPath.hruid = `${getEnvVar(EnvVars.UserContentPrefix)}test_conditions`; + learningPath.language = Language.English; + learningPath.title = 'Example learning path with conditional transitions'; + learningPath.description = 'This learning path was made for the purpose of testing conditional transitions'; + + const branchingLearningObject = testMultipleChoiceExample.createLearningObject(); + const extraExerciseLearningObject = dummyLearningObject( + 'test_extra_exercise', + Language.English, + 'Extra exercise (for students with difficulties)' + ).createLearningObject(); + const finalLearningObject = dummyLearningObject( + 'test_final_learning_object', + Language.English, + 'Final exercise (for everyone)' + ).createLearningObject(); + + const branchingNode = createLearningPathNode( + learningPath, + 0, + branchingLearningObject.hruid, + branchingLearningObject.version, + branchingLearningObject.language, + true + ); + const extraExerciseNode = createLearningPathNode( + learningPath, + 1, + extraExerciseLearningObject.hruid, + extraExerciseLearningObject.version, + extraExerciseLearningObject.language, + false + ); + const finalNode = createLearningPathNode( + learningPath, + 2, + finalLearningObject.hruid, + finalLearningObject.version, + finalLearningObject.language, + false + ); + + const transitionToExtraExercise = createLearningPathTransition( + branchingNode, + 0, + '$[?(@[0] == 0)]', // The answer to the first question was the first one, which says that it is difficult for the student to follow along. + extraExerciseNode + ); + const directTransitionToFinal = createLearningPathTransition(branchingNode, 1, '$[?(@[0] == 1)]', finalNode); + const transitionExtraExerciseToFinal = createLearningPathTransition(extraExerciseNode, 0, 'true', finalNode); + + branchingNode.transitions = [transitionToExtraExercise, directTransitionToFinal]; + extraExerciseNode.transitions = [transitionExtraExerciseToFinal]; + + learningPath.nodes = [branchingNode, extraExerciseNode, finalNode]; + + return { + branchingObject: branchingLearningObject, + finalObject: finalLearningObject, + extraExerciseObject: extraExerciseLearningObject, + learningPath: learningPath, + }; +} const example: LearningPathExample = { createLearningPath: () => { - const learningPath = new LearningPath(); - learningPath.hruid = 'test_conditions'; - learningPath.language = Language.English; - learningPath.title = 'Example learning path with conditional transitions'; - learningPath.description = 'This learning path was made for the purpose of testing conditional transitions'; - - const branchingLearningObject = testMultipleChoiceExample.createLearningObject(); - const extraExerciseLearningObject = dummyLearningObject( - 'test_extra_exercise', - Language.English, - 'Extra exercise (for students with difficulties)' - ).createLearningObject(); - const finalLearningObject = dummyLearningObject( - 'test_final_learning_object', - Language.English, - 'Final exercise (for everyone)' - ).createLearningObject(); - - const branchingNode = createLearningPathNode( - learningPath, - 0, - branchingLearningObject.hruid, - branchingLearningObject.version, - branchingLearningObject.language, - true - ); - const extraExerciseNode = createLearningPathNode( - learningPath, - 1, - extraExerciseLearningObject.hruid, - extraExerciseLearningObject.version, - extraExerciseLearningObject.language, - false - ); - const finalNode = createLearningPathNode( - learningPath, - 2, - finalLearningObject.hruid, - finalLearningObject.version, - finalLearningObject.language, - false - ); - - const transitionToExtraExercise = createLearningPathTransition( - branchingNode, - 0, - '$[?(@[0] == 0)]', // The answer to the first question was the first one, which says that it is difficult for the student to follow along. - extraExerciseNode - ); - const directTransitionToFinal = createLearningPathTransition(branchingNode, 1, '$[?(@[0] == 1)]', finalNode); - const transitionExtraExerciseToFinal = createLearningPathTransition(extraExerciseNode, 0, 'true', finalNode); - - branchingNode.transitions = [transitionToExtraExercise, directTransitionToFinal]; - extraExerciseNode.transitions = [transitionExtraExerciseToFinal]; - - learningPath.nodes = [branchingNode, extraExerciseNode, finalNode]; - - return learningPath; + return createConditionTestLearningPathAndLearningObjects().learningPath; }, }; diff --git a/backend/vitest.config.ts b/backend/vitest.config.ts index 302015fb..461d2018 100644 --- a/backend/vitest.config.ts +++ b/backend/vitest.config.ts @@ -4,5 +4,6 @@ export default defineConfig({ test: { environment: 'node', globals: true, + testTimeout: 10000, }, }); From dd21f46162c0b1ef4fde333659fcf866e7d7c5e4 Mon Sep 17 00:00:00 2001 From: Lint Action Date: Tue, 11 Mar 2025 10:59:51 +0000 Subject: [PATCH 150/180] style: fix linting issues met ESLint --- .../learning-paths/database-learning-path-provider.ts | 4 ++-- .../learning-path/database-learning-path-provider.test.ts | 6 +++--- .../test-assets/learning-paths/test-conditions-example.ts | 4 +--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/backend/src/services/learning-paths/database-learning-path-provider.ts b/backend/src/services/learning-paths/database-learning-path-provider.ts index 925f9f6b..e99048f7 100644 --- a/backend/src/services/learning-paths/database-learning-path-provider.ts +++ b/backend/src/services/learning-paths/database-learning-path-provider.ts @@ -112,9 +112,9 @@ async function convertNodes( function optionalJsonStringToObject(jsonString?: string): object | null { if (!jsonString) { return null; - } else { + } return JSON.parse(jsonString); - } + } /** diff --git a/backend/tests/services/learning-path/database-learning-path-provider.test.ts b/backend/tests/services/learning-path/database-learning-path-provider.test.ts index 81d4a149..1088cb2e 100644 --- a/backend/tests/services/learning-path/database-learning-path-provider.test.ts +++ b/backend/tests/services/learning-path/database-learning-path-provider.test.ts @@ -94,7 +94,7 @@ function expectBranchingObjectNode(result: LearningPathResponse, persTestData: { studentA: Student; studentB: Student }): LearningObjectNode { - let branchingObjectMatches = result.data![0].nodes.filter( + const branchingObjectMatches = result.data![0].nodes.filter( it => it.learningobject_hruid === persTestData.learningContent.branchingObject.hruid ); expect(branchingObjectMatches.length).toBe(1); @@ -156,7 +156,7 @@ describe('DatabaseLearningPathProvider', () => { .transitions .filter(it => it.next.hruid === persTestData.learningContent.finalObject.hruid) .length - ).toBe(0); // studentA picked the first option, therefore, there should be no direct path to the final object. + ).toBe(0); // StudentA picked the first option, therefore, there should be no direct path to the final object. expect( branchingObject .transitions @@ -183,7 +183,7 @@ describe('DatabaseLearningPathProvider', () => { .transitions .filter(it => it.next.hruid === persTestData.learningContent.finalObject.hruid) .length - ).toBe(1); // studentB picked the second option, therefore, there should be a direct path to the final object. + ).toBe(1); // StudentB picked the second option, therefore, there should be a direct path to the final object. expect( branchingObject .transitions diff --git a/backend/tests/test-assets/learning-paths/test-conditions-example.ts b/backend/tests/test-assets/learning-paths/test-conditions-example.ts index f06ff904..9ac8c4d6 100644 --- a/backend/tests/test-assets/learning-paths/test-conditions-example.ts +++ b/backend/tests/test-assets/learning-paths/test-conditions-example.ts @@ -80,7 +80,5 @@ export function createConditionTestLearningPathAndLearningObjects(){ } const example: LearningPathExample = { - createLearningPath: () => { - return createConditionTestLearningPathAndLearningObjects().learningPath; - }, + createLearningPath: () => createConditionTestLearningPathAndLearningObjects().learningPath, }; From 06bc1cb8bfdd7f3df788dd30f8d36509c46adbef Mon Sep 17 00:00:00 2001 From: Lint Action Date: Tue, 11 Mar 2025 10:59:55 +0000 Subject: [PATCH 151/180] style: fix linting issues met Prettier --- .../database-learning-path-provider.ts | 12 +-- .../learning-path-personalization-util.ts | 2 +- .../database-learning-path-provider.test.ts | 90 ++++++++----------- .../dummy/dummy-learning-object-example.ts | 6 +- .../test-essay/test-essay-example.ts | 4 +- .../test-multiple-choice-example.ts | 4 +- .../learning-paths/test-conditions-example.ts | 14 +-- 7 files changed, 60 insertions(+), 72 deletions(-) diff --git a/backend/src/services/learning-paths/database-learning-path-provider.ts b/backend/src/services/learning-paths/database-learning-path-provider.ts index e99048f7..a0bd6a47 100644 --- a/backend/src/services/learning-paths/database-learning-path-provider.ts +++ b/backend/src/services/learning-paths/database-learning-path-provider.ts @@ -97,9 +97,10 @@ async function convertNodes( learningobject_hruid: node.learningObjectHruid, version: learningObject.version, transitions: node.transitions - .filter((trans) => - !personalizedFor || isTransitionPossible(trans, optionalJsonStringToObject(lastSubmission?.content)) // If we want a personalized learning path, remove all transitions that aren't possible. - ).map((trans, i) => convertTransition(trans, i, nodesToLearningObjects)), // Then convert all the transition + .filter( + (trans) => !personalizedFor || isTransitionPossible(trans, optionalJsonStringToObject(lastSubmission?.content)) // If we want a personalized learning path, remove all transitions that aren't possible. + ) + .map((trans, i) => convertTransition(trans, i, nodesToLearningObjects)), // Then convert all the transition }; }) .toArray(); @@ -112,9 +113,8 @@ async function convertNodes( function optionalJsonStringToObject(jsonString?: string): object | null { if (!jsonString) { return null; - } - return JSON.parse(jsonString); - + } + return JSON.parse(jsonString); } /** diff --git a/backend/src/services/learning-paths/learning-path-personalization-util.ts b/backend/src/services/learning-paths/learning-path-personalization-util.ts index 648b7abc..29b8c5ec 100644 --- a/backend/src/services/learning-paths/learning-path-personalization-util.ts +++ b/backend/src/services/learning-paths/learning-path-personalization-util.ts @@ -36,6 +36,6 @@ export function isTransitionPossible(transition: LearningPathTransition, submitt if (submitted === null) { return false; // If the transition is not unconditional and there was no submission, the transition is not possible. } - const match = JSONPath({ path: transition.condition, json: {submission: submitted} }) + const match = JSONPath({ path: transition.condition, json: { submission: submitted } }); return match.length === 1; } diff --git a/backend/tests/services/learning-path/database-learning-path-provider.test.ts b/backend/tests/services/learning-path/database-learning-path-provider.test.ts index 1088cb2e..7e6124a3 100644 --- a/backend/tests/services/learning-path/database-learning-path-provider.test.ts +++ b/backend/tests/services/learning-path/database-learning-path-provider.test.ts @@ -5,7 +5,8 @@ import { LearningPath } from '../../../src/entities/content/learning-path.entity import { getLearningObjectRepository, getLearningPathRepository, - getStudentRepository, getSubmissionRepository + getStudentRepository, + getSubmissionRepository, } from '../../../src/data/repositories'; import learningObjectExample from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example'; import learningPathExample from '../../test-assets/learning-paths/pn-werking-example'; @@ -16,10 +17,10 @@ import learningObjectService from '../../../src/services/learning-objects/learni import { Language } from '../../../src/entities/content/language'; import { ConditionTestLearningPathAndLearningObjects, - createConditionTestLearningPathAndLearningObjects -} from "../../test-assets/learning-paths/test-conditions-example"; -import {Student} from "../../../src/entities/users/student.entity"; -import {LearningObjectNode, LearningPathResponse} from "../../../src/interfaces/learning-content"; + createConditionTestLearningPathAndLearningObjects, +} from '../../test-assets/learning-paths/test-conditions-example'; +import { Student } from '../../../src/entities/users/student.entity'; +import { LearningObjectNode, LearningPathResponse } from '../../../src/interfaces/learning-content'; async function initExampleData(): Promise<{ learningObject: LearningObject; learningPath: LearningPath }> { const learningObjectRepo = getLearningObjectRepository(); @@ -32,9 +33,9 @@ async function initExampleData(): Promise<{ learningObject: LearningObject; lear } async function initPersonalizationTestData(): Promise<{ - learningContent: ConditionTestLearningPathAndLearningObjects, - studentA: Student, - studentB: Student + learningContent: ConditionTestLearningPathAndLearningObjects; + studentA: Student; + studentB: Student; }> { const studentRepo = getStudentRepository(); const submissionRepo = getSubmissionRepository(); @@ -49,9 +50,9 @@ async function initPersonalizationTestData(): Promise<{ console.log(await getSubmissionRepository().findAll({})); const studentA = studentRepo.create({ - username: "student_a", - firstName: "Aron", - lastName: "Student" + username: 'student_a', + firstName: 'Aron', + lastName: 'Student', }); await studentRepo.save(studentA); const submissionA = submissionRepo.create({ @@ -61,14 +62,14 @@ async function initPersonalizationTestData(): Promise<{ submissionNumber: 0, submitter: studentA, submissionTime: new Date(), - content: '[0]' + content: '[0]', }); await submissionRepo.save(submissionA); const studentB = studentRepo.create({ - username: "student_b", - firstName: "Bill", - lastName: "Student" + username: 'student_b', + firstName: 'Bill', + lastName: 'Student', }); await studentRepo.save(studentB); const submissionB = submissionRepo.create({ @@ -78,7 +79,7 @@ async function initPersonalizationTestData(): Promise<{ submissionNumber: 1, submitter: studentB, submissionTime: new Date(), - content: '[1]' + content: '[1]', }); await submissionRepo.save(submissionB); @@ -86,16 +87,19 @@ async function initPersonalizationTestData(): Promise<{ learningContent: learningContent, studentA: studentA, studentB: studentB, - } + }; } -function expectBranchingObjectNode(result: LearningPathResponse, persTestData: { - learningContent: ConditionTestLearningPathAndLearningObjects; - studentA: Student; - studentB: Student -}): LearningObjectNode { +function expectBranchingObjectNode( + result: LearningPathResponse, + persTestData: { + learningContent: ConditionTestLearningPathAndLearningObjects; + studentA: Student; + studentB: Student; + } +): LearningObjectNode { const branchingObjectMatches = result.data![0].nodes.filter( - it => it.learningobject_hruid === persTestData.learningContent.branchingObject.hruid + (it) => it.learningobject_hruid === persTestData.learningContent.branchingObject.hruid ); expect(branchingObjectMatches.length).toBe(1); return branchingObjectMatches[0]; @@ -104,7 +108,7 @@ function expectBranchingObjectNode(result: LearningPathResponse, persTestData: { describe('DatabaseLearningPathProvider', () => { let learningObjectRepo: LearningObjectRepository; let example: { learningObject: LearningObject; learningPath: LearningPath }; - let persTestData: { learningContent: ConditionTestLearningPathAndLearningObjects, studentA: Student, studentB: Student } + let persTestData: { learningContent: ConditionTestLearningPathAndLearningObjects; studentA: Student; studentB: Student }; beforeAll(async () => { await setupTestApp(); @@ -137,13 +141,13 @@ describe('DatabaseLearningPathProvider', () => { expectToBeCorrectLearningPath(result.data![0], example.learningPath, learningObjectsOnPath); }); - it("returns the correct personalized learning path", async () => { + it('returns the correct personalized learning path', async () => { // For student A: let result = await databaseLearningPathProvider.fetchLearningPaths( [persTestData.learningContent.learningPath.hruid], persTestData.learningContent.learningPath.language, 'the source', - {type: 'student', student: persTestData.studentA} + { type: 'student', student: persTestData.studentA } ); expect(result.success).toBeTruthy(); expect(result.data?.length).toBe(1); @@ -151,25 +155,17 @@ describe('DatabaseLearningPathProvider', () => { // There should be exactly one branching object let branchingObject = expectBranchingObjectNode(result, persTestData); - expect( - branchingObject - .transitions - .filter(it => it.next.hruid === persTestData.learningContent.finalObject.hruid) - .length - ).toBe(0); // StudentA picked the first option, therefore, there should be no direct path to the final object. - expect( - branchingObject - .transitions - .filter(it => it.next.hruid === persTestData.learningContent.extraExerciseObject.hruid) - .length - ).toBe(1); // There should however be a path to the extra exercise object. + expect(branchingObject.transitions.filter((it) => it.next.hruid === persTestData.learningContent.finalObject.hruid).length).toBe(0); // StudentA picked the first option, therefore, there should be no direct path to the final object. + expect(branchingObject.transitions.filter((it) => it.next.hruid === persTestData.learningContent.extraExerciseObject.hruid).length).toBe( + 1 + ); // There should however be a path to the extra exercise object. // For student B: result = await databaseLearningPathProvider.fetchLearningPaths( [persTestData.learningContent.learningPath.hruid], persTestData.learningContent.learningPath.language, 'the source', - {type: 'student', student: persTestData.studentB} + { type: 'student', student: persTestData.studentB } ); expect(result.success).toBeTruthy(); expect(result.data?.length).toBe(1); @@ -178,18 +174,10 @@ describe('DatabaseLearningPathProvider', () => { branchingObject = expectBranchingObjectNode(result, persTestData); // However, now the student picks the other option. - expect( - branchingObject - .transitions - .filter(it => it.next.hruid === persTestData.learningContent.finalObject.hruid) - .length - ).toBe(1); // StudentB picked the second option, therefore, there should be a direct path to the final object. - expect( - branchingObject - .transitions - .filter(it => it.next.hruid === persTestData.learningContent.extraExerciseObject.hruid) - .length - ).toBe(0); // There should not be a path anymore to the extra exercise object. + expect(branchingObject.transitions.filter((it) => it.next.hruid === persTestData.learningContent.finalObject.hruid).length).toBe(1); // StudentB picked the second option, therefore, there should be a direct path to the final object. + expect(branchingObject.transitions.filter((it) => it.next.hruid === persTestData.learningContent.extraExerciseObject.hruid).length).toBe( + 0 + ); // There should not be a path anymore to the extra exercise object. }); it('returns a non-successful response if a non-existing learning path is queried', async () => { const result = await databaseLearningPathProvider.fetchLearningPaths( diff --git a/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts b/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts index 14f62828..2f2e78ad 100644 --- a/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts +++ b/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts @@ -3,7 +3,7 @@ import { LearningObject } from '../../../../src/entities/content/learning-object import { Language } from '../../../../src/entities/content/language'; import { loadTestAsset } from '../../../test-utils/load-test-asset'; import { DwengoContentType } from '../../../../src/services/learning-objects/processing/content-type'; -import {EnvVars, getEnvVar} from "../../../../src/util/envvars"; +import { EnvVars, getEnvVar } from '../../../../src/util/envvars'; /** * Create a dummy learning object to be used in tests where multiple learning objects are needed (for example for use @@ -22,8 +22,8 @@ export function dummyLearningObject(hruid: string, language: Language, title: st learningObject.content = Buffer.from('Dummy content'); learningObject.returnValue = { callbackUrl: `/learningObject/${hruid}/submissions`, - callbackSchema: "[]" - } + callbackSchema: '[]', + }; return learningObject; }, createAttachment: {}, diff --git a/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts b/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts index c0c18c6a..d57c7a33 100644 --- a/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts +++ b/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts @@ -16,8 +16,8 @@ const example: LearningObjectExample = { learningObject.contentType = DwengoContentType.GIFT; learningObject.returnValue = { callbackUrl: `/learningObject/${learningObject.hruid}/submissions`, - callbackSchema: '["antwoord vraag 1"]' - } + callbackSchema: '["antwoord vraag 1"]', + }; learningObject.content = loadTestAsset('learning-objects/test-essay/content.txt'); return learningObject; }, diff --git a/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts b/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts index c5dcdc94..a634878a 100644 --- a/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts +++ b/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts @@ -16,8 +16,8 @@ const example: LearningObjectExample = { learningObject.contentType = DwengoContentType.GIFT; learningObject.returnValue = { callbackUrl: `/learningObject/${learningObject.hruid}/submissions`, - callbackSchema: '["antwoord vraag 1"]' - } + callbackSchema: '["antwoord vraag 1"]', + }; learningObject.content = loadTestAsset('learning-objects/test-multiple-choice/content.txt'); return learningObject; }, diff --git a/backend/tests/test-assets/learning-paths/test-conditions-example.ts b/backend/tests/test-assets/learning-paths/test-conditions-example.ts index 9ac8c4d6..07857235 100644 --- a/backend/tests/test-assets/learning-paths/test-conditions-example.ts +++ b/backend/tests/test-assets/learning-paths/test-conditions-example.ts @@ -3,17 +3,17 @@ import { Language } from '../../../src/entities/content/language'; import testMultipleChoiceExample from '../learning-objects/test-multiple-choice/test-multiple-choice-example'; import { dummyLearningObject } from '../learning-objects/dummy/dummy-learning-object-example'; import { createLearningPathNode, createLearningPathTransition } from './learning-path-utils'; -import {LearningObject} from "../../../src/entities/content/learning-object.entity"; -import {EnvVars, getEnvVar} from "../../../src/util/envvars"; +import { LearningObject } from '../../../src/entities/content/learning-object.entity'; +import { EnvVars, getEnvVar } from '../../../src/util/envvars'; export type ConditionTestLearningPathAndLearningObjects = { - branchingObject: LearningObject, - extraExerciseObject: LearningObject, - finalObject: LearningObject, - learningPath: LearningPath + branchingObject: LearningObject; + extraExerciseObject: LearningObject; + finalObject: LearningObject; + learningPath: LearningPath; }; -export function createConditionTestLearningPathAndLearningObjects(){ +export function createConditionTestLearningPathAndLearningObjects() { const learningPath = new LearningPath(); learningPath.hruid = `${getEnvVar(EnvVars.UserContentPrefix)}test_conditions`; learningPath.language = Language.English; From 3f04d2fd4df6d26cb3c212a31d897a6fd8ac00c9 Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Tue, 11 Mar 2025 12:18:07 +0100 Subject: [PATCH 152/180] feat(backend): Gepersonaliseerde leerpaden via API Mogelijkheid toegevoegd om via de API optioneel een gepersonaliseerde variant van een leerpad voor een student of groep aan te vragen. --- backend/src/controllers/learning-paths.ts | 27 ++++++++-- .../learning-path-personalization-util.ts | 54 ++++++++++++++++++- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/backend/src/controllers/learning-paths.ts b/backend/src/controllers/learning-paths.ts index 8e654d02..fca86bfb 100644 --- a/backend/src/controllers/learning-paths.ts +++ b/backend/src/controllers/learning-paths.ts @@ -2,7 +2,12 @@ import { Request, Response } from 'express'; import { themes } from '../data/themes.js'; import { FALLBACK_LANG } from '../config.js'; import learningPathService from '../services/learning-paths/learning-path-service'; -import { NotFoundException } from '../exceptions'; +import {BadRequestException, NotFoundException} from '../exceptions'; +import {Language} from "../entities/content/language"; +import { + PersonalizationTarget, personalizedForGroup, + personalizedForStudent +} from "../services/learning-paths/learning-path-personalization-util"; /** * Fetch learning paths based on query parameters. @@ -13,6 +18,22 @@ export async function getLearningPaths(req: Request, res: Response): Promise theme.hruids); } - const learningPaths = await learningPathService.fetchLearningPaths(hruidList, language, `HRUIDs: ${hruidList.join(', ')}`); + const learningPaths = await learningPathService.fetchLearningPaths(hruidList, language as Language, `HRUIDs: ${hruidList.join(', ')}`, personalizationTarget); res.json(learningPaths.data); } diff --git a/backend/src/services/learning-paths/learning-path-personalization-util.ts b/backend/src/services/learning-paths/learning-path-personalization-util.ts index 648b7abc..c671e9a0 100644 --- a/backend/src/services/learning-paths/learning-path-personalization-util.ts +++ b/backend/src/services/learning-paths/learning-path-personalization-util.ts @@ -2,12 +2,64 @@ import { LearningPathNode } from '../../entities/content/learning-path-node.enti import { Student } from '../../entities/users/student.entity'; import { Group } from '../../entities/assignments/group.entity'; import { Submission } from '../../entities/assignments/submission.entity'; -import { getSubmissionRepository } from '../../data/repositories'; +import { + getClassRepository, + getGroupRepository, + getStudentRepository, + getSubmissionRepository +} from '../../data/repositories'; import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier'; import { LearningPathTransition } from '../../entities/content/learning-path-transition.entity'; import { JSONPath } from 'jsonpath-plus'; export type PersonalizationTarget = { type: 'student'; student: Student } | { type: 'group'; group: Group }; + +/** + * Shortcut function to easily create a PersonalizationTarget object for a student by his/her username. + * @param username Username of the student we want to generate a personalized learning path for. + * If there is no student with this username, return undefined. + */ +export async function personalizedForStudent(username: string): Promise { + const student = await getStudentRepository().findByUsername(username); + if (student) { + return { + type: "student", + student: student + } + } else { + return undefined; + } +} + +/** + * Shortcut function to easily create a PersonalizationTarget object for a group by class name, assignment number and + * group number. + * @param classId Id of the class in which this group was created + * @param assignmentNumber Number of the assignment for which this group was created + * @param groupNumber Number of the group for which we want to personalize the learning path. + */ +export async function personalizedForGroup(classId: string, assignmentNumber: number, groupNumber: number): Promise { + const clazz = await getClassRepository().findById(classId); + if (!clazz) { + return undefined; + } + const group = await getGroupRepository().findOne({ + assignment: { + within: clazz, + id: assignmentNumber, + }, + groupNumber: groupNumber + }) + if (group) { + return { + type: "group", + group: group + } + } else { + return undefined; + } +} + /** * Returns the last submission for the learning object associated with the given node and for the student or group */ From 78267a241657c3f54f21a20e1c779b2b5f7ea28c Mon Sep 17 00:00:00 2001 From: Lint Action Date: Tue, 11 Mar 2025 11:18:55 +0000 Subject: [PATCH 153/180] style: fix linting issues met ESLint --- .../learning-paths/learning-path-personalization-util.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/services/learning-paths/learning-path-personalization-util.ts b/backend/src/services/learning-paths/learning-path-personalization-util.ts index 02d7d9ab..b7145bf3 100644 --- a/backend/src/services/learning-paths/learning-path-personalization-util.ts +++ b/backend/src/services/learning-paths/learning-path-personalization-util.ts @@ -26,9 +26,9 @@ export async function personalizedForStudent(username: string): Promise Date: Tue, 11 Mar 2025 11:18:59 +0000 Subject: [PATCH 154/180] style: fix linting issues met Prettier --- backend/src/controllers/learning-paths.ts | 20 +++++----- .../learning-path-personalization-util.ts | 39 +++++++++---------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/backend/src/controllers/learning-paths.ts b/backend/src/controllers/learning-paths.ts index fca86bfb..7a98ab2e 100644 --- a/backend/src/controllers/learning-paths.ts +++ b/backend/src/controllers/learning-paths.ts @@ -2,12 +2,9 @@ import { Request, Response } from 'express'; import { themes } from '../data/themes.js'; import { FALLBACK_LANG } from '../config.js'; import learningPathService from '../services/learning-paths/learning-path-service'; -import {BadRequestException, NotFoundException} from '../exceptions'; -import {Language} from "../entities/content/language"; -import { - PersonalizationTarget, personalizedForGroup, - personalizedForStudent -} from "../services/learning-paths/learning-path-personalization-util"; +import { BadRequestException, NotFoundException } from '../exceptions'; +import { Language } from '../entities/content/language'; +import { PersonalizationTarget, personalizedForGroup, personalizedForStudent } from '../services/learning-paths/learning-path-personalization-util'; /** * Fetch learning paths based on query parameters. @@ -26,10 +23,10 @@ export async function getLearningPaths(req: Request, res: Response): Promise theme.hruids); } - const learningPaths = await learningPathService.fetchLearningPaths(hruidList, language as Language, `HRUIDs: ${hruidList.join(', ')}`, personalizationTarget); + const learningPaths = await learningPathService.fetchLearningPaths( + hruidList, + language as Language, + `HRUIDs: ${hruidList.join(', ')}`, + personalizationTarget + ); res.json(learningPaths.data); } diff --git a/backend/src/services/learning-paths/learning-path-personalization-util.ts b/backend/src/services/learning-paths/learning-path-personalization-util.ts index b7145bf3..df344917 100644 --- a/backend/src/services/learning-paths/learning-path-personalization-util.ts +++ b/backend/src/services/learning-paths/learning-path-personalization-util.ts @@ -2,12 +2,7 @@ import { LearningPathNode } from '../../entities/content/learning-path-node.enti import { Student } from '../../entities/users/student.entity'; import { Group } from '../../entities/assignments/group.entity'; import { Submission } from '../../entities/assignments/submission.entity'; -import { - getClassRepository, - getGroupRepository, - getStudentRepository, - getSubmissionRepository -} from '../../data/repositories'; +import { getClassRepository, getGroupRepository, getStudentRepository, getSubmissionRepository } from '../../data/repositories'; import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier'; import { LearningPathTransition } from '../../entities/content/learning-path-transition.entity'; import { JSONPath } from 'jsonpath-plus'; @@ -23,12 +18,11 @@ export async function personalizedForStudent(username: string): Promise { +export async function personalizedForGroup( + classId: string, + assignmentNumber: number, + groupNumber: number +): Promise { const clazz = await getClassRepository().findById(classId); if (!clazz) { return undefined; @@ -48,16 +46,15 @@ export async function personalizedForGroup(classId: string, assignmentNumber: nu within: clazz, id: assignmentNumber, }, - groupNumber: groupNumber - }) + groupNumber: groupNumber, + }); if (group) { return { - type: "group", - group: group - } - } - return undefined; - + type: 'group', + group: group, + }; + } + return undefined; } /** From 001bd11cca877a39615a9b42f6a1d02721ac19d4 Mon Sep 17 00:00:00 2001 From: Laure Jablonski Date: Wed, 12 Mar 2025 08:55:19 +0100 Subject: [PATCH 155/180] frontend: functionaliteit van idp werkt in login --- frontend/src/views/LoginPage.vue | 92 +++++++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 6 deletions(-) diff --git a/frontend/src/views/LoginPage.vue b/frontend/src/views/LoginPage.vue index 1cee79fb..a538a80c 100644 --- a/frontend/src/views/LoginPage.vue +++ b/frontend/src/views/LoginPage.vue @@ -1,4 +1,5 @@ @@ -59,22 +59,22 @@ :to="`/${role}/${userId}/assignment`" class="menu_item" > - {{ t('assignments') }} + {{ t("assignments") }}
  • {{ t('classes') }}{{ t("classes") }}
  • {{ t('discussions') }} + >{{ t("discussions") }} +
  • diff --git a/frontend/src/i18n/i18n.ts b/frontend/src/i18n/i18n.ts index 7cd6bf10..6e25cc19 100644 --- a/frontend/src/i18n/i18n.ts +++ b/frontend/src/i18n/i18n.ts @@ -1,4 +1,4 @@ -import { createI18n } from 'vue-i18n'; +import { createI18n } from "vue-i18n"; // Import translations import en from "@/i18n/locale/en.json"; @@ -6,11 +6,11 @@ import nl from "@/i18n/locale/nl.json"; import fr from "@/i18n/locale/fr.json"; import de from "@/i18n/locale/de.json"; -const savedLocale = localStorage.getItem('user-lang') || 'en'; +const savedLocale = localStorage.getItem("user-lang") || "en"; const i18n = createI18n({ locale: savedLocale, - fallbackLocale: 'en', + fallbackLocale: "en", messages: { en: en, nl: nl, diff --git a/frontend/src/main.ts b/frontend/src/main.ts index e82313b5..e4843dae 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -1,8 +1,8 @@ -import {createApp} from "vue"; +import { createApp } from "vue"; // Vuetify import "vuetify/styles"; -import {createVuetify} from "vuetify"; +import { createVuetify } from "vuetify"; import * as components from "vuetify/components"; import * as directives from "vuetify/directives"; import i18n from "./i18n/i18n.ts"; @@ -11,7 +11,6 @@ import i18n from "./i18n/i18n.ts"; import App from "./App.vue"; import router from "./router"; - const app = createApp(App); app.use(router);